Ok i have an mvc app. and im trying to get my delete to work. Basically i want it so when i click delete it takes me to a page saying "are you sure?" i have that working, the problem is catching the request and actually doing the delete. i tried diffrent methods. as below.
public ActionResult Delete(int id)
{
var something = friendsDB.Friends.Single(a => a.Id == id);
return View(something);
}
[HttpPost]
public ActionResult Delete(int id, string confirmButton)
{
var something = friendsDB.Friends.Single(a => a.Id == id);
// For simplicity, we're allowing deleting of albums
// with existing orders We've set up OnDelete = Cascade
// on the Album->OrderDetails and Album->Carts relationships
friendsDB.DeleteObject(something);
friendsDB.SaveChanges();
return View("Index");
}
That doesnt work cause, deleteobject and savechanges claim
"C:\Users\Mtszc\Documents\Visual
Studio
2010\Projects\Test\Test\Content\Controllers\DownloadsController.cs(36,23):
error CS1061: 'Test.Models.FriendsDB'
does not contain a definition for
'DeleteObject' and no extension method
'DeleteObject' accepting a first
argument of type
'Test.Models.FriendsDB' could be found
(are you missing a using directive or
an assembly reference?)"
the second thing i tried was
public ActionResult Delete(int id)
{
var something = friendsDB.Friends.Single(a => a.Id == id);
return View(something);
}
[HttpDelete]
public ActionResult Delete(Friend myFriend)
{
try
{
friendsDB.Friends.DeleteOnSubmit(myFriend);
friendsDB.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
that didnt work. it compiled but when i click delete, and it takes me to the page where i say im sure i want to delete, it returns view, which was the catch, meaning the try failed.
this is a simple sql database i made, Id, name, link. and im using linq to sql class. i c can create and view, but not delete.
Try something like this instead.
var rowToDelete = friendsDB.Friends.Single(a => a.ID == myFriend.ID);
friendsDB.Friends.DeleteOnSubmit(rowToDelete);
friendsDB.SubmitChanges();
That would be a simple way of taking care of the record delete with Linq. I apologize if the syntax isn't perfect since I'm writing it on the fly out of my head.
By the way there are some GREAT videos made by the guys over at Microsoft for learning ASP.NET MVC as well as LINQ. Check these out.
http://www.asp.net/mvc
Cheers
Ok for who ever views this i solved the problem. Through hours of digging, i solved the problem. For anyone who made a sql data base and made a model class for it using linq to sql this is how to get delete to work.
public ActionResult Delete(int id)
{
var something = friendsDB.Friends.Single(a => a.Id == id);
return View(something);
}
[HttpPost]
public ActionResult Delete(int id, string confirmButton)
{
var sigh = friendsDB.Friends.Single(a => a.Id == id);
try
{
friendsDB.Friends.DeleteOnSubmit(sigh);
friendsDB.SubmitChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
with this, create a strongly typed delete view.
The error messages appear to be confusing you.
"C:\Users\Mtszc\Documents\Visual Studio 2010
\Projects\Test\Test\Content\Controllers\DownloadsController.cs(36,23): error
CS1061: 'Test.Models.FriendsDB' does not contain a definition for 'DeleteObject'
and no extension method 'DeleteObject' accepting a first argument of
type 'Test.Models.FriendsDB' could be found (are you missing a using directive
or an assembly reference?)"
Is not referring to the MVC Action, it is referring to your Test.Models.FriendsDB method call:
friendsDB.DeleteObject(something);
It sounds like you have not Defined the method "DeleteObject" on your friendsDB model or you do not have a overloaded method that accepts a 'Test.Models.FriendsDB' object type.
Secondly, don't confuse HTTP Methods (Get, Post, Put, Delete) with what you are trying to accomplish. "Put" and "Delete" are methods I don't believe web browsers use often if at all. Most requests are GET unless you are submitting a form, then they are POST. Adding the HttpDelete will most likely render that Action useless. If you only want a Delete action from a form submit then add HttpPost
Related
Yesterday I upgraded my ASP.NET Core 5 Web API to .Net 6. Today I thought I'd also migrate from Newtonsoft.Json to System.Text.Json.
The first thing I did was to remove the Microsoft.AspNetCore.Mvc.NewtonsoftJson package from my project. I also removed the .AddNewtonsoftJson() statement from the services.AddControllers() part of Startup.cs.
I then renamed all using Newtonsoft.Json; to using System.Text.Json;, all [JsonProperty] decorators to [JsonPropertyName], etc, etc.
I'm almost error-free now, but I've hit a stumbling block with my HttpPatch action methods. The "ModelState" class seems to be a member of Microsoft.AspNetCore.Mvc.NewtonsoftJson, which I removed. I could re-add it, as well as re-add .AddNewtonsoftJson() to services.AddControllers() in Startup.cs, but that would seem a step backward in what I'm trying to achieve (which is to completely cut off from Newtonsoft.Json).
This is the error VS is showing:
Error CS1503 Argument 2: cannot convert from 'Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary' to 'System.Action<Microsoft.AspNetCore.JsonPatch.JsonPatchError>'
Any ideas on how I can make HttpPatch work without depending on Newtonsoft.Json?
My HttpPatch action method looks like this:
[HttpPatch("{id:int}")]
public async Task<ActionResult<DocGroup>> PatchDocumentGroup([FromRoute] int id, [FromBody] JsonPatchDocument<DocGroup> patchDoc)
{
if (patchDoc == null)
return BadRequest(ModelState);
var documentGroup = await _context.DocGroups.FindAsync(id);
if (documentGroup == null)
{
return NotFound();
}
patchDoc.ApplyTo(documentGroup, ModelState);
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _context.SaveChangesAsync();
return new ObjectResult(documentGroup);
}
I am trying to use .andExpect(model().attributeHasFieldErrors in my unit test.
According to this page java.lang.AssertionError: No BindingResult for attribute: abc is caused because the view returned by tested controller is a redirect: "redirect:/xyz/add".
But at the same time, most of #PostMapping(/...) use redirect. Does it mean that in this kind of cases there is no way of knowing if attributeHasFieldErrors ?
It seems to be possible - in this sample it seems to be working - BUT I am confused on this:
There testProcessUpdateOwnerFormHasErrors test-method (second method from bottom in above link) performs POST [ i.e. mockMvc.perform(post(... ] , and expects view name that is returned by GET method in Controller class.
That is, #GetMapping("/owners/{ownerId}/edit") returns "owners/createOrUpdateOwnerForm" and #PostMapping("/owners/{ownerId}/edit") returns "redirect:/owners/{ownerId}" in Controller. And above test performing POST expects "owners/createOrUpdateOwnerForm". Should it not expect "redirect:/owners/{ownerId}" ?
I am confused.
Can someone explain proper way of implementing attributeHasFieldErrors?
Typically, you use redirect when there are no errors, to avoid multiple POSTS. When
there is an error, the normal way to proceed would be to redisplay the same view with the error messages.
Something like :
#PostMapping("/")
public String processForm(#Valid UserForm userForm, BindingResult bindingResult, Model model) {
if ( ! bindingResult.hasErrors()) {
Long id = service.saveUser(userForm.getUser());
return "redirect:/user/"+id;
} else {
return "calcForm";
}
}
I'm pretty sure that I'm doing something really stupid. Please have a look and let me know what I'm doing wrong.
Here is my ActionLink
#Html.ActionLink("Edit","Edit","UserProfile", new { id = Model.ApplicationUserId },null)
When I click this it throws the bad request exception and also I noticed the url is
https://localhost:44304/UserProfile/Edit/92b1347c-c9ec-4728-8dff-11bc9f935d0b
not
https://localhost:44304/UserProfile/Edit?userId=92b1347c-c9ec-4728-8dff-11bc9f935d0b
I have a HTTPGET Edit method in my controller and it takes UserId. When I pass the route values manually it works.Please help me.
Your help is much appreciated and someday, will pay it forward.
Thanks!
Cheers!
If the parameter you are expecting is userId, then use the #Html.ActionLink like this:
#Html.ActionLink("Edit","Edit","UserProfile", new { userId = Model.ApplicationUserId },null)
If you pass the parameter with name id, then the MVC will route like you mentioned:
https://localhost:44304/UserProfile/Edit/92b1347c-c9ec-4728-8dff-11bc9f935d0b
Which is great, but your method should be something expecting the parameter with the appropriate name:
// GET: /UserProfile/Edit/{id}
public ActionResult Edit(String id){
//your code
return View();
}
If you have some time, check out this ASP.NET MVC Routing Overview with a lot more details.
You need change parameter for your controller action Edit from userId to id - best variant.
public Edit(int id)
{
}
Or
#Html.ActionLink("Edit","Edit","UserProfile", new { userId = Model.ApplicationUserId },null)
I'm using EF 4.1 Code First. I have an entity defined with a property like this:
public class Publication
{
// other stuff
public virtual MailoutTemplate Template { get; set; }
}
I've configured this foreign key using fluent style like so:
modelBuilder.Entity<Publication>()
.HasOptional(p => p.Template)
.WithMany()
.Map(p => p.MapKey("MailoutTemplateID"));
I have an MVC form handler with some code in it that looks like this:
public void Handle(PublicationEditViewModel publicationEditViewModel)
{
Publication publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
publication.Template = _mailoutTemplateRepository.Get(publicationEditViewModel.Template.Id);
if (publication.Id == 0)
{
_publicationRepository.Add(publication);
}
else
{
_publicationRepository.Update(publication);
}
_unitOfWork.Commit();
}
In this case, we're updating an existing Publication entity, so we're going through the else path. When the _unitOfWork.Commit() fires, an UPDATE is sent to the database that I can see in SQL Profiler and Intellitrace, but it does NOT include the MailoutTemplateID in the update.
What's the trick to get it to actually update the Template?
Repository Code:
public virtual void Update(TEntity entity)
{
_dataContext.Entry(entity).State = EntityState.Modified;
}
public virtual TEntity Get(int id)
{
return _dbSet.Find(id);
}
UnitOfWork Code:
public void Commit()
{
_dbContext.SaveChanges();
}
depends on your repository code. :) If you were setting publication.Template while Publication was being tracked by the context, I would expect it to work. When you are disconnected and then attach (with the scenario that you have a navigation property but no explicit FK property) I'm guessing the context just doesn't have enough info to work out the details when SaveChanges is called. I'd do some experiments. 1) do an integration test where you query the pub and keep it attached to the context, then add the template, then save. 2) stick a MailOutTemplateId property on the Publicaction class and see if it works. Not suggesting #2 as a solution, just as a way of groking the behavior. I"m tempted to do this experiment, but got some other work I need to do. ;)
I found a way to make it work. The reason why I didn't initially want to have to do a Get() (aside from the extra DB hit) was that then I couldn't do this bit of AutoMapper magic to get the values:
Publication publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
However, I found another way to do the same thing that doesn't use a return value, so I updated my method like so and this works:
public void Handle(PublicationEditViewModel publicationEditViewModel)
{
Publication publication = _publicationRepository.Get(publicationEditViewModel.Id);
_mappingEngine.Map(publicationEditViewModel, publication);
// publication = Mapper.Map<PublicationEditViewModel, Publication>(publicationEditViewModel);
publication.Template = _mailoutTemplateRepository.Get(publicationEditViewModel.Template.Id);
if (publication.Id == 0)
{
_publicationRepository.Add(publication);
}
else
{
_publicationRepository.Update(publication);
}
_unitOfWork.Commit();
}
I'm injecting an IMappingEngine now into the class, and have wired it up via StructureMap like so:
For<IMappingEngine>().Use(() => Mapper.Engine);
For more on this, check out Jimmy's AutoMapper and IOC post.
I'm haing a few problems updating a row in my database using Linq2Sql.
Inside of my model I have two methods for updating and saving from my controller, which in turn receives an updated model from my view.
My model methods like like:
public void Update(Activity activity)
{
_db.Activities.InsertOnSubmit(activity);
}
public void Save()
{
_db.SubmitChanges();
}
and the code in my Controller likes like:
[HttpPost]
public ActionResult Edit(Activity activity)
{
if (ModelState.IsValid)
{
UpdateModel<Activity>(activity);
_activitiesModel.Update(activity);
_activitiesModel.Save();
}
return View(activity);
}
The problem I'm having is that this code inserts a new entry into the database, even though the model item i'm inserting-on-submit contains a primary key field.
I've also tried re-attaching the model object back to the data source but this throws an error because the item already exists.
Any pointers in the right direction will be greatly appreciated.
UPDATE:
I'm using dependancy injection to instantiate my datacontext object as follows:
IMyDataContext _db;
public ActivitiesModel(IMyDataContext db)
{
_db = db;
}
There should be an insert in case of the InsertOnSubmit method usage, this is an expected behaviour.
We recommend the Attach() method usage in your Update() method implementation. In case you have IsVersion column in the entity then everything is simple, in the other case you will have to pass the original values also to the Attach call. More information is available here in MSDN.
I fixed this issue by re-obtaining and updating my object in the Update method.
Instead of trying to re-attach or get the data context to realise it was the same object that belonged to it before I basically did as follows:
[HttpPost]
public ActionResult Edit(Activity activity)
{
Activity myActivity = activitiesModel.getActivityById(activity.id);
myActivity.name = activity.name;
myActivity.date = activity.date;
_dbContext.SubmitChanges();
return View(activity);
}
This isn't my exact code and to be more precise, I created another partial class to my datacontext and stored my update code in there.