ASP.NET MVC can't read cookies - asp.net-mvc

This ought to be simple enough, although I find I can only set cookies but not read them back, despite my browser showing me the cookie.
In my HomeController I set the cookie once a user enters a valid string:
[HttpPost]
public ActionResult Index(string fMemberCode)
{
try
{
// TODO: controller-->member table module-->member data gateway-->DB
// Check member num against member table
// Return cookie if exists
// Return error if not
MembersModule membersModule = new MembersModule();
int memberId = membersModule.AuthMember(fMemberCode);
if (memberId > 0)
{
HttpCookie mCookie = new HttpCookie("MMedia");
mCookie.Value = memberId.ToString();
Response.Cookies.Add(mCookie);
}
else { }
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Then later on, in a different context, the LibraryController needs to check the cookie is present:
public LibraryController()
{
// TODO
// Check member cookie present
int id = int.Parse(Request.Cookies["Media"].Value);
if (id > 0)
this.module = new LibraryModule(id);
else throw new Exception("Invalid cookie");
}
However, when stepping through the code in VS2012 when the line of execution in LibraryController reaches:
int id = int.Parse(Request.Cookies["Media"].Value);
The exception is thrown: Object reference not set to an instance of an object

You can't access the Request property in the constructor of your controller. It doesn't exist at that point in the controller life cycle.
Perhaps an action or controller filter might help you.

Related

Not able to update the data using entity framework

I have following code. in that i am trying to update my data. but i am getting error message:
An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code
Additional information: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
Here is my code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="CompanyId,Address,EstbalishYear,Email,IsActive")] CompanyMaster companymaster)
{
if (companymaster.CompanyId == 0)
{
return View(companymaster);
}
CompanyMaster company = db.CompanyMasters.SingleOrDefault(x => x.CompanyId == companymaster.CompanyId);
companymaster.Name = company.Name;
companymaster.InsertedBy = company.InsertedBy;
companymaster.InsertedTime = company.InsertedTime;
companymaster.UpdatedBy = 1;
companymaster.UpdatedTime = DateTime.Now;
ModelState.Remove("Name");
if (ModelState.IsValid)
{
db.Entry(companymaster).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companymaster);
}
Please explain me how can I fix this error message?
This is because you are working with two object instances of a company master, which in reality is a single entity, with the same ID.
One (companyMaster) comes as an argument to the Edit method, via binding.
The other one (company) you are selecting from the database through db.CompanyMasters by ID
What you can do is
Select company by ID, as you do now
Set company properties from companyMaster object (vice-versa, not like you do now)
Save the company object
Please find the sample code below.
Please also note that the best practice is not to use your persistence entity model in UI layer, but rather define a DTO with a minimum set of required fields, and then map it to your entity either manually or using AutoMapper.
[HttpPost] [ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include="CompanyId,Address,EstbalishYear,Email,IsActive")] CompanyMaster companymaster)
{
if (companymaster.CompanyId == 0)
{
return View(companymaster);
}
CompanyMaster company = db.CompanyMasters.SingleOrDefault(x => x.CompanyId == companymaster.CompanyId);
company.Address = companymaster.Address;
company.EstbalishYear= companymaster.EstbalishYear;
company.Email = companymaster.Email;
company.IsActive= companymaster.IsActive;
company.UpdatedBy = 1;
company.UpdatedTime = DateTime.Now;
ModelState.Remove("Name");
if (ModelState.IsValid)
{
db.SaveChanges();
return RedirectToAction("Index");
}
return View(companymaster);
}

View/Model data isn't refreshing/changing after post/postback, even though I'm using the PRG pattern

Update I have saved my problem a long time ago. The problem was that I was trying to call the view model on the wrong view method! I was calling the base view method (Document), instead of one of it's derived method (like NewDocument, PDFDocument, etc.) Thus it was only giving me the Documents data, which didn't change. I was looking and using the wrong view method all the time... Stephen, when you asked me
"Why do you create derived classes in a method but then return only the base class"
I couldn't answer the question at the time because I didn't even know myself, until I remember that originally, the method wasn't returning the base class. I only changed it so that it can work with the base view method, which was wrong in the first place!
That's what I get for only getting 3-4 hours of sleep in 3 days. Everything works right now. Thanks.
I'm having a hard time trying to figure out why the data in my view isn't changing after I do a post. Originally I was doing it via return View() and it worked, but since it was a partial view, the page didn't look great, so I was reading up and saw that it was better to do it by Post-Redirect-Get pattern (PRG) and to use an id value to retrieve the values instead of sending the entire model via Tempdata. I even used ModelState.Clear() and that didn't even work. When I debugged the code, the model only has the values from when I first called it.
Here's part of my Get controller:
NewDocument Get Controller
[DocumentAuthenticationFilter]
public ActionResult NewDocument(int? id = null)
{
// This doesn't work. The view keeps on showing the data from View(Services.CreateNewDocument()).
if (id != null)
{
return View(Services.GetdocumentViewModelData(DocEnum.Section.NEW_DOC_INDEX, (int)id));
}
// This works fine
return View(Services.CreateNewDocument());
}
And here's the post that calls the redirect:
NewDocument Post controller
[HttpPost]
[ValidateAntiForgeryToken]
[MultipleButton(Name = "action", Argument = "AddDocuments")]
//[OutputCache(Duration = 30, VaryByParam = "*")]
public ActionResult AddDocumentViewModel(FormCollection frm, DocumentViewModel dvm)
{
try
{
if (ModelState.IsValid)
{
int? DocID = Services.AddingNewDocument(dvm);
// See, I even tried to clear it.
ModelState.Clear();
return base.RedirectToAction("NewDocument", new { id = DocID });
}
else
{
// Display errors in the modal
}
return base.RedirectToAction("NewDocument");
}
And here's the old way I did it:
NewDocument Post controller
[HttpPost]
[ValidateAntiForgeryToken]
[MultipleButton(Name = "action", Argument = "AddDocuments")]
//[OutputCache(Duration = 30, VaryByParam = "*")]
public ActionResult AddDocumentViewModel(FormCollection frm, DocumentViewModel dvm)
{
try
{
if (ModelState.IsValid)
{
Services.AddingNewDocument(ref dvm);
dvm.NewRecordMode = DocEnum.Action.UPDATE;
// It worked, but only the partial view showed, and not the entire view.
return PartialView("_NewDocument", dvm);
}
else
{
// Display errors in the model
}
return base.RedirectToAction("NewDocument");
}
Could it be because I'm using a custom model binding?
My Custom Model Binding
public class BaseClassModelBinder : DefaultModelBinder
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var modelType = bindingContext.ModelType;
var modelTypeValue = controllerContext.Controller.ValueProvider.GetValue("ViewModel");
if (modelTypeValue == null)
throw new Exception("View does not contain the needed derived model type name");
var modelTypeName = modelTypeValue.AttemptedValue;
var type = modelType.Assembly.GetTypes().SingleOrDefault(x => x.IsSubclassOf(modelType) && x.Name == modelTypeName);
if (type == null)
{
throw new Exception(String.Format("Derived model type {0} not found", modelTypeName));
}
var instance = bindingContext.Model ?? base.CreateModel(controllerContext, bindingContext, type);
bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => instance, type);
return base.BindModel(controllerContext, bindingContext);
}
}
EDIT: And here's the GetDocumentViewModelData code:
GetDocumentFromViewModelData
public static DocumentViewModel GetDocumentViewModelData(DocEnum.Section docType, int id)
{
switch (docType)
{
case DocEnum.Section.NEW_DOCUMENT_INDEX:
// NewDocumentTypeViewModel is a child to DocumentTypeViewModel
DocumentTypeViewModel nd = NewDocumentService.GetViewModelByID(id);
return nd;
case DocEnum.Section.PDF_DOCUMENT:
DocumentTypeViewModel pdfvm = PDFDocumentService.GetViewModelByID(id);
return pdfvm;
case DocEnum.Section.XLS_DOCUMENT:
DocumentTypeViewModel xlsvm = XLSDocumentService.GetViewModelByID(id);
return xlsvm;
}
return null;
}
Edit: Also adding the GetViewModelByID function
GetViewModelByID
public static DocumentTypeViewModel GetViewModelByID(int id)
{
docEntities db = new docEntities();
NewDocumentTypeViewModel vm = new NewDocumentTypeViewModel();
// Calls a stored procedure called Select_Documents_ByID(id) to get the note entry
// that was submitted.
List<Select_Documents_ByID_Result> prevNotes = db.Select_Documents_ByID(id).ToList();
StringBuilder sNotes = new StringBuilder();
foreach (var note in prevNotes)
{
sNotes.AppendFormat("{0} - {1}: {2}\n\n", note.CreatedDate.ToString("yyyy-MM-dd HH:mm"), note.username, note.Entry);
}
vm.PreviousNotes = sNotes.ToString();
return vm;
}
Edit: I did a direct creation of the view model inside the Get controller, and it's the same result. when i debugged the view itself, the values from the new view model don't show up. Instead, the values from the initial view model, View(Services.CreateNewDocument()), shows.
[DocumentAuthenticationFilter]
public ActionResult NewDocument(int? id = null)
{
// Right here I created the view model to test thing, but I'm getting the same results. Nothing has changed.
if (id != null)
{
var d = new NewDocumentTypeViewModel(1, "Help!");
// This property is from the base class, DocumentTypeViewModel
d.DocumentTitle = "Testing!";
return View(d);
// Inside the view itself, none of the values in the view model, including the one
// belonging to the base class. It still shows the initial values.
}
// This works fine
// Or maybe not...
return View(Services.CreateNewDocument());
}
Edit: I wanted to see if it was also doing the same thing for the initial call to the view return View(Services.CreateNewDocument()), and decided to change the value for documentTitle in the base class from New Document to a randomly-generated number, after the object has been created.
Here's the code for DocumentTypeViewModel's default constructor:
public DocumentTypeViewModel()
{
DocumentTitle = "New Document";
NewRecordMode = DocEnum.Action.ADD;
DocumentID = 0;
}
And here's the Services.CreateNewDocument() code where I change the DocumentTitle after the View Model has been created.
public DocumentTypeViewModel CreateNewDocument()
{
DocumentTypeViewModel dtvm = new DocumentTypeViewModel();
Random r = new Random();
dtvm.DocumentTitle = r.Next(5, Int32.MaxValue).ToString();
return dtvm;
}
Now in the View, when I call DocumentTitle:
<div class="label-text-group">
#Html.LabelFor(model => model.DocumentTitle)
#Html.EditorFor(model => model.DocumentTitle)
</div>
You would expect to see a randomly-generated number every time the View gets called. Nope, what you would see is "New Document". Weird.
It's seems that Services.GetDocumentViewModelData() is not exactly working correctly. It only carries the values created by the base class' constructor when a view is created, not any values that have been added or changed within GetDocumentViewModelData() itself. Why is that? What's going on? Please help anybody!
I have solved it. Look at the Update section on top. Thanks Stephen.

object instantiation - mvc simultaneous connections

This is a pretty basic question but just want help understanding how a server interacts with the browser/computer connecting to it.
When a user hits the Create() action it sends the Currentclaim object to the view. Because the _currentclaim variable is null it creates a new object with certain properties. If I load up another browser (IE, Safari) and use the app it isn't a 'fresh start' as _currentclaim has retained the properties that were given to it in the other browser.
public class ClaimsController : Controller
{
private static ClaimViewModel _currentclaim;
private static ClaimViewModel Currentclaim
{
get
{//If _currentclaim is null then create it. Return it.
if (_currentclaim == null)
_currentclaim = GetClaimViewModel();
return _currentclaim;
}
set//set value of Currentclaim.
{
_currentclaim = value;
}
}
public static ClaimViewModel GetClaimViewModel()
{
return new ClaimViewModel()
{
ClaimID = 101,
SubmissionUserID = 10,
DateSubmitted = DateTime.Now,
LineViewModels = new List<LineViewModel>() {
new LineViewModel() {MeetingDate=DateTime.Now,SubCatID=1},
}
};
}
public ActionResult Create()
{
return View(Currentclaim);
}
[HttpPost]
public ActionResult Create(ClaimViewModel claimvm)
{ claimvm.SubmissionUserID = Currentclaim.SubmissionUserID;
claimvm.DateSubmitted = Currentclaim.DateSubmitted;
_currentclaim = claimvm;
return View("Summary", Currentclaim);
}
}
I just want to be reasssured that when a user connects to my web application from wherever it is hosted that his or her session will start with a null object (and not one instantiated by someone else .... if that makes sense)

How to handle if an invalid Id is passed to the action

I am currently doing a project in MVC 3 and can't figure out if a user passes an invalid id (let's say 23233), how can i display a message to the user that item with this id does not exist?
Assuming this is ASP.NET, use Find() in your DbSet to find a user with that Id. If the result is null, use something like RedirectToAction() to send the user to a page explaining the problem.
The VS scaffolding system already does something similar, except it returns an HttpNotFound() instead in the automatically generated code. You can use its logic as a starting point.
first.
You are create a checker method for id.
public bool idChecker(string id)
{
try
{
double numeric = -1;
bool retval = double.TryParse(id, out numeric);
return retval;
}
catch (Exception)
{
return false;
}
}
and you will use idChecker method.
public ActionResult YourActionMethod(string id)
{
if (!idChecker(id))
return Content("Invalid ID"); // or your code
else
return View(); // or your code.
}

How can I have an object which can be accessed from different controllers?

I'm working with ASP.Net MVC4, I customize my login, this is ok, I would like save this object USER and I can access from differents controllers and differents Areas. I was trying to defined this object as "static" but I can't acces to values of object:
if (Servicio.ValidarUsuario())
{
string Mensaje = "";
Models.AdmUsuario oAdmUsuario = new Models.AdmUsuario();
oAdmUsuario.Au_codusuario = login.UserName;
Servicio.RetornaEntidad<Models.AdmUsuario>(ref Mensaje, "admsis.adm_usuario", oAdmUsuario.getPk(), oAdmUsuario);
***Models.AdmUsuario.UserWeb = oAdmUsuario;***
FormsAuthentication.SetAuthCookie(login.UserName, false);
Session["Modulo"] = null;
Session["Menu"] = null;
return RedirectToAction("index", "raMainReclamo", new { area = "Reclamos" });
}
In the model I define:
public static AdmUsuario UserWeb;
But I can't access to value.
Do you have any idea, how I can to access the values ​​of an object from different controllers in different areas?
You need a way to store the object between requests. You could put the object in Session Memory and pull it back out.
{
// Other Code
Session["AdmUsuario"] = oAdmUsuario;
return RedirectToAction("index", "raMainReclamo", new { area = "Reclamos" });
}
Controller in Reclamos Area
public class raMainReclamoController : Controller
{
public ActionResult Index() {
var oAdmUsuario = Session["AdmUsuario"] as Models.AdmUsuario;
// Other Code
}
}
However, the a more standard approach would be to persist the object to a database and then pull it back out. You could read up on using Entity Framework to access a sql database. I like to use RavenDB for storage as it makes saving objects really easy.
** UPDATE IN RESPONSE TO COMMENTS **
This is just psuedo code as I don't know what you are using to connect to postgres.
{
// Other Code
oAdmUsuario = postgresContext.Store(oAdmUsuario);
postgresContext.SaveChanges();
return RedirectToAction("index", "raMainReclamo", new { area = "Reclamos", id = oAdmnUsuario.Id });
}
Controller in Reclamos Area
public class raMainReclamoController : Controller
{
public ActionResult Index(int id) {
var oAdmUsuario = postgresContext.GetById<Models.AdmUsuario>(id);
// Other Code
}

Resources