ASP.NET MVC: No record added to database after POST - asp.net

[HttpPost]
public ActionResult Create(FormCollection collection)
{
UpdateModel(collection);
context.SaveChanges();
return RedirectToAction("Index", new {controller = "Home"});
}
The action succeed, but there was no recored inserted into the database. Why?
I do not want to manually create a object by getting each value from each field in form collection.

UpdateModel(collection);
context.SaveChanges();
You didn't made any changes to the context in order to expect something to get saved. Entity Framework (assuming this is what you are using) works with objects. So you need a model and persist this model into the database. So your controller action could look like this:
[HttpPost]
public ActionResult Create(Product product)
{
_repository.Create(product);
return RedirectToAction("Index", new {controller = "Home"});
}
where the _repository variable is some interface which defines the operations on your models. Using an interface here allows you to separate your data access logic from your controller logic. In the implementation of this repository you could be using any data access technology you like such as EF or NHibernate, it's just that your controller shouldn't know about it.

Are you sure the context is open and it's the same from which your object has been extracted ? is the object is still connected to the context ?
usually you create a new context in each call, you need to attach the object to the context change it state to modified and than use SaveChanges.
Otherwise, nothing is done.
context.Customers.Attach(myCustomre);
context.ObjectStateManager.ChangeObjectState(myCustomre, System.Data.EntityState.Modified);
context.SaveChanges();
and for insert:
context.Customers.AddObject(newCustomer);
context.SaveChanges();

Related

How to Update Model in ASP NET MVC 6?

Scenario: How to update a model?
ASP MVC 6
I am trying to update a model. For passing the model information to the client(browser/app) I am using the DTO.
Question 1: For updating, should I post the whole object back?
Question 2: Is there a way I can easily pass only the information that is updated? If yes, how?
Question 3: Can I use JSON Patch for updation?
Question 2: Is there a way I can easily pass only the information that
is updated? If yes, how?
Yes. You should create a view model which should have only those properties needed for the view.
Let's assume your use case is to build a view which allows user to edit only their last name.
public class EditUserViewModel
{
public int Id {set;get;}
public string LastName {set;get;}
}
And in your Get
public ActionResult Edit(int id)
{
var user = yourUserRepository.GetUser(id);
if(user!=null)
{
var v = new EditUserViewModel { Id=id,LastName=user.LastName};
return View(v);
}
return View("NotFound");
}
And the view
#model EditUserViewModel
#using(Html.BeginForm())
{
#Html.TextBoxFor(s=>S.LastName)
#Html.HiddenFor(s=>s.Id)
<input type="submit" id="saveBtn" />
}
and your HttpPost action
[HttpPost]
public ActionResult Edit(EditUserViewModel model)
{
// Since you know you want to update the LastName only,
// read model.LastName and use that
var existingUser = yourUserRepository.GetUser(model.Id);
existingUser.LastName = model.LastName;
yourUserRepository.Save();
// TO DO: redirect to success page
}
Assuming yourUserRepository is an object of your data access classes abstraction.
Question 1: For updating, should I post the whole object back?
Depends on what you want from the end user. With this view model approach, It is going to post only the Id and LastName and that is our use case.
Can I use JSON Patch for updating?
Since you are only sending the data which needs to be updated (partial data), you should be fine.
If you want,you may simply serialize your form data(which has only Id and LastName) and use jQuery post method to send it to your server.
$(function(){
$("#saveBtn").click(function(e){
e.preventDefault(); //prevent default form submit
var _form=$(this).closest("form");
$.post(_form.attr("action"),_form.serialize(),function(res){
//do something with the response.
});
});
});
To prevent overposting, you can use a binding whitelist using Bind attribute on your HttpPost action method. But the safest strategy is to use a view model class that exactly matches what the client is allowed to send.
Instead of this
UpdateModel(model);
You now can call this
await TryUpdateModelAsync(model);

Front end ASP.NET MVC4 as one project, and an ASP.NET Web API as another project in same solution - how to call WebAPI from front end?

I have an ASP.NET MVC4 front end as one project in my solution, and a separate ASP.NET Web API as another project in the same solution. The Web API will contain all of my CRUD operations.
2 questions
How do I call my Web API from my front end to perform CRUD operations? I have my entity data model defined in my Web API project, and I will need to bind my front end views to it, how would I do that?
Once this is deployed to my web servers, the front end will reside on one server, and the Web API will reside on another server (the server that holds most of our web services). So, I guess along the same lines, how would I call the Web API from my front end once deployed? I understand Web API's are simply called with an HTTP request, but in terms of passing my models (which are defined in my Web API project) into my Views (in my front end project), how can I do this?
While Kevin is right, I did this the non-Ajax way. Keep in mind that I am working with JSON data, so this is centered around JSON.
In your controller page, remove anything that has to do with DbContext, Entity Framework, etc. The reason is by default, the controller will want to perform CRUD operations by calling the DbContext, and we don't want this. We want to call the WebAPI instead to do this.
First and foremost, declare some member variables in your controller. The rest of your controller will utilize these:
HttpClient client = new HttpClient();
HttpResponseMessage response = new HttpResponseMessage();
Uri contactUri = null;
In your controller, create a constructor for your controller, as such:
public ContactController()
{
// set base address of WebAPI depending on your current environment
client.BaseAddress = new Uri("http://server/YourAPI/");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
Replace the Index action's code with something like the following. Note that the only relevant pieces are the client.GetAsync() call and the var contacts assignment. Everything else is not necessary for the context of this problem. The value inside the client.GetAsync() should be the name of your controller, prepended by any custom routing you set up in your WebApiConfig.cs - in my case, I added the api part in my route to distinguish between API calls and normal calls:
public ActionResult Index()
{
response = client.GetAsync("api/contact").Result;
if (response.IsSuccessStatusCode)
{
var contacts = response.Content.ReadAsAsync<IEnumerable<Contact>>().Result;
return View(contacts);
}
else
{
// add something here to tell the user hey, something went wrong
return RedirectToAction("Index");
}
}
Replace the Create action (the HttpPost action) with something like the following. Again, the only important piece is the client.PostAsJsonAsync() part - this is what calls the WebAPI's POST action which takes care of, in my case, inserting a new record into the database:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Contact contact)
{
// Create a new product
response = client.PostAsJsonAsync("api/contact", contact).Result;
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
// add something here to tell the user hey, something went wrong
return RedirectToAction("Index");
}
}
Replace the Edit action (the non-HttpPost action) with something like the following. This was a little tricky because in order to edit, you had to retrieve the record first, so basically, the HttpPost version of Edit will contain somewhat similar code, with an additional line of code that performs the edit POST (PUT). Below, we're getting the response from the WebAPI by passing it a specific record ID. So, just like for Index (GET), we are doing the same thing only passing in the ID so we only get back one record. Then, we cast the response to an actual object that can be operated on in the View:
public ActionResult Edit(int id = 0)
{
response = client.GetAsync(string.Format("api/contact/{0}", id)).Result;
Contact contact = response.Content.ReadAsAsync<Contact>().Result;
if (contact == null)
{
return HttpNotFound();
}
return View(contact);
}
Replace the Edit action (the HttpPost action) with something like the following. Below, we're getting the record to be edited by calling client.GetAsync() and passing in the primary key as a parameter (contact_id). Then, we're getting the RequestUri from that response and saving it. Then, we're calling client.PutAsJsonAsync() and passing in the Uri.PathAndQuery (what we just saved) as well as the object to be edited.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(Contact contact)
{
response = client.GetAsync(string.Format("api/contact/{0}", contact.contact_id)).Result;
contactUri = response.RequestMessage.RequestUri;
response = client.PutAsJsonAsync(contactUri.PathAndQuery, contact).Result;
if (response.IsSuccessStatusCode)
{
return RedirectToAction("Index");
}
else
{
// add something here to tell the user hey, something went wrong
return RedirectToAction("Index");
}
}
Replace the Delete action (the non-HttpPost action) with something like the following. So again, we're getting the record from the database by simply calling client.GetAsync() and casting it to an actual object my app knows of.
public ActionResult Delete(int id = 0)
{
response = client.GetAsync(string.Format("api/contact/{0}", id)).Result;
Contact contact = response.Content.ReadAsAsync<Contact>().Result;
if (contact == null)
{
return HttpNotFound();
}
return View(contact);
}
Finally, replace the Delete action (the HttpPost action) with something like the following. Again, we're doing something similar to that of the Edit action. We are getting the record to be deleted, casting it to an object, and then passing that object into a client.DeleteAsync() call, as shown below.
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
response = client.GetAsync(string.Format("api/contact/{0}", id)).Result;
contactUri = response.RequestMessage.RequestUri;
response = client.DeleteAsync(contactUri).Result;
return RedirectToAction("Index");
}
You can call your Web API from the client using jQuery ajax method. But since you are calling from a site other than where the Web API is deployed you will have to use JSONP, instead of JSON. Take a look at this QA to see how you use JSONP with Web API. Your models will be passed as JSON which you will have to render on the client side, instead of using Razor to render it on the server side. I would use something like Knockout to create a View Model on the client that will bind your model to the HTML elements on the client.

spring auto populate user details for every request

I have a spring MVC based web application. Currently in my web page i am showing the user first name and last name after user logs in. The way i am doing this is, for every HttpServletRequest that comes into #Controller#RequestMapping, i get the Principal object and get the user details from it, then populate the ModelMap with firstname and lastname attribute. For example here is the sample code
#Autowired
private SecurityDetails securityDetails;
#RequestMapping(method = RequestMethod.GET)
public String showWelcomePage(HttpServletRequest request,
HttpServletResponse response, ModelMap model, Principal principal)
{
securityDetails.populateUserName(model, principal);
... lot of code here;
return "home";
}
public boolean populateUserName(ModelMap model, Principal principal) {
if (principal != null) {
Object ob = ((Authentication)principal).getPrincipal();
if(ob instanceof MyUserDetails)
{
MyUserDetails ud = (MyUserDetails)ob;
model.addAttribute("username", ud.getFirstName() + " " + ud.getLastName());
}
return true;
}
else
{
logger.debug("principal is null");
return false;
}
}
My problem is i am having to call the populateUserName method for every RequestMapping. Is there a elegant way, like populating this in Interceptor method, which will result in this method being called just in one place for entire application?
Its good that you want to prevent duplication of code. Here is how you can do it.
Create a custom HandlerInterceptor http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/HandlerInterceptor.html
Post handle is the only method of interest for us, for the others return defaults.
In the post handle method, you have access to the model and view returned from your controller, go ahead and add whatever you want.
The Principal will not be available directly here, you will have to look it up using some code like SecurityContextHolder.getContext().getAuthentication().getPrincipal()
Wire the handler interceptor to intercept all or some of your controllers.
Hope this helps.
You can use either Servlet Filters or Spring Interceptors.
BTW, where do you populate the Principal from?
In any case, thats where you should do this populating stuff.

asp.net mvc custom model binding in an update entity scenario

Hi I have a question about model binding. Imagine you have an existing database entity displayed in a form and you'd like to edit some details, some properties eg createddate etc are not bound to the form, during model binding, these properties are not assigned to the model as they are not on the http post data or querystrong etc, hence their properties are null. In my controller method for update , Id just like to do
public ActionResult Update( Entity ent)
{
//Save changes to db
}
but as some properties are null in ent, they override the existing database fields which are not part of the form post data, What is the correct way to handle this? Ive tried hidden fields to hold the data, but model binding does not seem to assign hidden fields to the model. Any suggestions would be appreciated
You shouldn't be sending your entity to your view, you should send a slim version of it called a DTO (data transfer object) or ViewModel.
Only send the properties to the view (and hence the form that gets posted back) that you want the user to update with that action.
In your POST handler you can then validate and copy the properties across to your entity.
an AutoMapper can help if you have lots of properties
something like:
public class User
{
int id;
string name;
string email;
}
public class EditUserEmailDto
{
string email;
}
// get
public ActionResult EditEmail(int id,)
{
return View("EditEmail", new EditUserEmailDto());
}
// post
public ActionResult EditEmail(int id, EditUserEmailDto dto)
{
if(!ModelState.IsValid)
return View("EditEmail", dto);
var user = userRepo.Get(id);
user.email = dto.email;
userRepo.Save(user);
return;
}

Proper way of using FormCollection in ASP.NET MVC2 Create Method?

I am currently developing an application with the new ASP.NET MVC2 framework. Originally I started writing this application in the ASP.NET MVC1 and I'm basically just updating it to MVC2.
My problem here is, that I don't really get the concept of the FormCollection object vs. the old Typed object.
This is my current code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
try
{
Member member = new Member();
member.FirstName = collection["FirstName"];
member.LastName = collection["LastName"];
member.Address = collection["Address"];
// ...
return RedirectToAction("Details", new { id = member.id });
}
catch
{
return View("Error");
}
}
This is the Code from the MVC1 application:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(Member member)
{
try
{
memberRepository.Add(member);
memberRepository.Save();
return RedirectToAction("Details", new { id = member.id });
}
catch
{
}
return View(new MemberFormViewModel(member, memberRepository));
}
What are the benefits of switching to FormCollection in MVC2 and more importantly - how is it used properly?
You had the FormCollection object in v1 as well. But it is more preferred to use a typed object. So if you are already doing that, then continue doing so.
By using FormCollection, you wind up manually matching your post data or query string key/values into values to use in your code using string typing (resulting in stringly-typed code), when instead the built-in Model Binding can do this for you if you use form models, aka "typed objects."
I think by using the FormCollection, you would probably also lose the ability to use the handy Data Annotation (slash Validation) attributes on your model objects as well, which are designed for use with typed object model binding.
Additionally, unit testing can become much more cumbersome once you start touching your controller.Request.Form. You might find yourself having to mock and setup an HttpContextBase, and an HttpRequestBase just to have that mock request's .Form property return the NameValueCollection that you are wanting your test to see. Contrast this to letting model binding do the work for you such as:
// Arrange
var myModel = new MyModel( Property1 = "value1", Property2 = "value2");
// Act
var myResult = myController.MyActionMethod(myModel);
// Assert
// whatever you want the outcome to be
In summary, I would recommend against using FormCollection to the maximum extent possible.

Resources