asp.net passing an id between views in different controllers - asp.net

So I have two models with a one to many relationship. Callout, and shift offer. Callout can have many shift offers.
I want to pass my callout_id to the shift-offer controller. I've done this by modifying the Index() method as follows:
public async Task<ActionResult> Index(long? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
Debug.WriteLine("Callout ID cannot be null");
}
var shift_Offers = db.Shift_Offers.Where(s => s.callout_id_fk == id);
return View(await shift_Offers.ToListAsync());
}
I've also modified one of my HTML action links to call a different page:
#Html.ActionLink("View Callout",
"Index",
"ShiftOffer",
new { area = ""},
new { id=item.callout_id_pk }) |
But here's the kicker, when I try to call Index(long id), it's throwing that bad request error. Why isn't my ID being passed like it is with the default scaffolded links?

Try below
#Html.ActionLink("View Callout",
"Index",
"ShiftOffer",
new { id=item.callout_id_pk },
new { area = ""})

Related

Saving current user name(logged) into Form database ASP.Net MVC

I am newbie in ASP.NET. Is there a possible way to save the current logged user into the form database when the form is submitted?
(i.e) When multiple registered users enter a form and click save their user name is saved into the contents of form database.
I had googled it but couldn't find related topics (maybe I used the wrong keywords). If methods are available kindly suggest link.
[Edit]
I have used asp.net identity for authentication.
My current code for save
public ActionResult NewPR()
{
var depts = _context.Depts.ToList();
var currencytypes = _context.Currencytypes.ToList();
var viewModel = new NewPRViewModel
{
PRview = new PRview(),
Currencytypes = currencytypes,
};
return View("NewPR", viewModel);
}
[HttpPost]
public ActionResult Save(PRview prview)
{
if (!ModelState.IsValid)
{
var viewModel = new NewPRViewModel
{
PRview = prview,
Currencytypes = _context.Currencytypes.ToList()
};
return View("NewPR", viewModel);
}
if (prview.Id == 0)
_context.PRviews.Add(prview);
else
{
var prviewInDb = _context.PRviews.Single(c => c.Id == prview.Id);
prviewInDb.SupplierName = prview.SupplierName;
prviewInDb.Brand = prview.Brand;
prviewInDb.Qty = prview.Qty;
prviewInDb.Unitprice = prview.Unitprice;
}
_context.SaveChanges();
return RedirectToAction("Index", "PRview");
}

Why Is The Selected Value Different Between Using Route ID and Action Parameter in SelectList

I have a SelectList in my action method. The selected value for SelectList is coming from the action method parameter. The action and view are simple like below:
// Recipe Action
public ActionResult Recipe(int? recipeId)
{
ViewBag.RecipeID = new SelectList(_recipsRecipes, "RecipeID", "RecipeName", recipeId);
return View(new Recipe());
}
//Recipe View
#model RecipeDemo.Models.Recipe
#Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty)
I'm using ActionLink below to call the Recipe action.
#Html.ActionLink("Recipe", "Recipe", "Home", new { recipeId = 2 }, null)
It works like I expect, the DropDownList is showing the selected value as the No. 2 (recipeId = 2) item.
Problem
When I change the Recipe action parameter by using route id, like below:
//Recipe View
public ActionResult Recipe(int? id)
{
ViewBag.RecipeID = new SelectList(_recipsRecipes, "RecipeID", "RecipeName", id);
return View(new Recipe());
}
//Recipe View (Same View as above)
#model RecipeDemo.Models.Recipe
#Html.DropDownList("RecipeID", (SelectList)ViewBag.RecipeID, string.Empty)
And I'm using ActionLink below to call the Recipe action.
#Html.ActionLink("Recipe", "Recipe", "Home", new { id = 2 }, null)
The DropDownList is NOT showing the selected value, (id = 2) item. The selection is instead empty.
But I have the correct id value in the SelectList. see below:
Why is this, does anyone know the explanation?
Update:
The model is below:
public class Recipe
{
public int RecipeID { get; set; }
public string RecipeName { get; set; }
}
Well that was certainly interesting. After first confirming the issue with the code you provided, I experimented around and believe I have the root cause. Basically, you are using the same variable name way to often and the model binder appears to be getting confused. You have RecipeId in your route, RecipeId in your View Model and RecipeId as the name of your view bag variable. By altering my variable names, the SelectList works as expected.
The primary issue is naming your SelectList RecipeId which matches a property in your model. When you send the new Recipe(), the model binder is attempting to use that value. In your first example, since you have RecipeId defined in the URL, it is getting it from there. In the second example, there is no RecipeId to pull from the URL and it is null in the model.
Controller
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
private List<Recipe> Recipes;
public HomeController()
{
Recipes = new List<Recipe>
{
new Recipe {RecipeId = 1, RecipeName = "Test - 1"},
new Recipe {RecipeId = 2, RecipeName = "Test - 2"},
new Recipe {RecipeId = 3, RecipeName = "Test - 3"},
};
}
public ActionResult Index(int? id)
{
ViewBag.MyList = new SelectList(Recipes, "RecipeID", "RecipeName", id);
return View(new Recipe());
}
}
}
Index View
#model MvcApplication1.Models.Recipe
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#Html.DropDownList("MyRecipeId", (SelectList)ViewBag.MyList)
Basically, vary your parameter names a little bit more to help prevent the model binder from getting confused and/or pulling information from the wrong place.
You can verify this in your second example by sending this in your return statement:
Return View(New Recipe{RecipeId = 3});
The option value with 3 will be selected regardless of what the actual Id sent was.
EDIT
An even better option would be to do what I said to do as an example above. By changing your Action to this:
public ActionResult Index(int? id)
{
ViewBag.MyList = new SelectList(Recipes, "RecipeID", "RecipeName");
return View(new Recipe(RecipeId = id));
}
You can leave your view unchanged. Now, the SelectList will pull from the model that you are sending.

Setting Up Multiple Actions

I was wondering if it was possible to have more than 1 action in the link. For example, If I wanted to have multiple links such as:
http://www.mywebsite.com/(CONTROLLER)/(ID)/(ACTION)
[http://]www.mywebsite.com/user/Micheal/EditMovies
[http://]www.mywebsite.com/user/Micheal/EditFavorites
Is there some sort of way to do this? If not, do I have to specify multiple id's in the function and then use a case to determine which page they are going to be sent to?
In my UserController.cs I have:
public ActionResult Index(string username)
{
if (username != null)
{
try
{
var userid = (Membership.GetUser(username, false).ProviderUserKey);
Users user = entity.User.Find(userid);
return View(user);
}
catch (Exception e)
{
}
}
return RedirectToAction("", "Home");
}
In my Routes I have:
routes.MapRoute(
name: "User",
url: "User/{username}",
defaults: new { controller = "User", action = "Index" }
);
What I'm trying to make it do is have additional functions for second actions so I can do something like:
User/{username}/{actionsAdditional}
And In my UserController I can put more actions which will leader to the second action actionsAdditional
public ActionResult Index(string username)
{
if (username != null)
{
try
{
var userid = (Membership.GetUser(username, false).ProviderUserKey);
Users user = entity.User.Find(userid);
return View(user);
}
catch (Exception e)
{
}
}
return RedirectToAction("", "Home");
}
public ActionResult EditFavorites()
{
//DoStuff
}
You could do this multiple ways, here's just one:
Set up a route to handle this:
routes.MapRoute("UserEditsThings",
"user/{id}/edit/{thingToEdit}",
new { controller = "UserController", action="Edit" },
new { thingToEdit = ValidThingsToEditConstraint() }
);
Then your action in the User Controller should look like this:
public ActionResult Edit(ThingToEdit thingToEdit) {
ThingToEditViewModel viewModel = new ThingToEditViewModel(thingToEdit);
return View(viewModel);
}
The RouteConstraint is what would take their input (the thingToEdit) and make sure it was valid (you could do this in a few places - like in a Custom ModelBinder):
public class ValidThingsToEditConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
//simplistic implementation simply to show what's possible.
return values['thingToEdit'] == "Favorites" || values['thingToEdit'] == "Movies";
}
}
Now, that way, you can have one method to Edit both Movies and Favorites, and you simply add a parameter to show what 'type' of thing they're editing.
If you wanted to keep your current route, you should be able to do the following:
routes.MapRoute("UserEditsThings",
"user/{id}/edit{thingToEdit}",
new { controller = "UserController", action="Edit" },
new { thingToEdit = ValidThingsToEditConstraint() }
);
I've been away from ASP.NET MVC for about 7 months, so this could be a little rusty. It has not been tested for syntax errors and bits of python may shine through. It should get you there, though.

Change State to EntityState.Modified raised error

I have the following Asp.Net MVC 4 scaffold code.
//
// POST: /Detail/Edit/5
[HttpPost]
public ActionResult Edit(Detail detail)
{
var dd = Details.FirstOrDefault(d => d.DetailId == detail.DetailId);
if (dd == null)
{
return HttpNotFound();
}
detail.UpdatedBy = User.Identity.Name;
detail.UpdateTime = DateTime.Now;
if (ModelState.IsValid)
{
_db.Entry(detail).State = EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index", new { id = detail.MasterId });
}
return View(dealDetail);
}
However, the line _db.Entry(detail).State = EntityState.Modified; raise the following error. What's the correct way to update the detail line of a master/detail editing scenery?
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
This line:
var dd = Details.FirstOrDefault(d => d.DetailId == detail.DetailId);
will cause loading of Detail entity from the database. Now you have two Details with the same Id but only one (the one loaded by that query) can be used for persistence. You can change your code to:
if (!Details.Any(d => d.DetailId == detail.DetailId))
{
return HttpNotFound();
}
or update the attached detail (dd) for example by:
// All values of detail entity must be set in your HTTP post!
_db.Entry(dd).CurrentValues.SetValues(detail);

ASP.NET MVC create a new database record

I've been learning asp.net mvc 3. So, basically I'm trying to create a new record in database. However, I'm trying to keep a particular record predefined
public ActionResult Create()
{
var dc = new ServicesDataContext();
var model = new Maping();
var query = (from m in dc.Customers
where m.CustomerId == model.CustomerID
select m.CustomerId);
ViewData["CustomerID"] = query.First();
return View(model);
}
//
// POST: /Customerservice/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude="CustomerServiceMappingID")] Maping serviceToCreate, FormCollection form)
{
if (!ModelState.IsValid)
return View();
var dc = new ServicesDataContext();
dc.Mapings.InsertOnSubmit(serviceToCreate);
try
{
dc.SubmitChanges();
}
catch (Exception e)
{
}
try
{
var id = Int32.Parse(form["CustomerID"]);
ViewData["CustomerID"] = id;
return RedirectToAction("Index", new { id = id });
}
catch
{
return RedirectToAction("INDEX", "Home");
}
}
So this is what I did. So, the case is that id value in second action method is what i needed. However the second method gets redirectd to index so viewdata value is lost.And the thing i did in the first crate method is wrong because no value is assigned. So, can u please help me with this problem.
Use TempData, not ViewData - it will be valid until it is read again. Also why are you adding it into viewdata when it is being passed as a parameter in the RedirectToAction?

Resources