Asp.net 5 - VNext ViewData property in ViewResult is Null - asp.net-core

I'm using Asp.net 5 for a small application and i'm having a little trouble with returning a ViewResult from an orchestrator.
Where in previous versions of MVC we've done this:
return new ViewResult
{
ViewName = "Index",
ViewData = {Model = _formViewModelBuilder.BuildModel()}
};
In MVC 6 this throws a null reference exception. Setting the model property of the ViewData is invalid as the value of ViewData is null? I believe this has something to do with dependency injection but i can't find a concrete explanation anywhere as to why this behavior is happening.
The simplest way i can get this to work is something like:
return new ViewResult
{
ViewName = "Index",
ViewData = new ViewDataDictionary<FormViewModel>(ViewData, model)
};
This uses the Microsoft.AspNet.Mvc.Controller.ViewData property. I can pass this property through to the orchestrator but i'm not sure if this is just plain wrong and i'm missing a trick here?
Any help would be appreciated.
Thanks

I managed to get an answer over at github. The viewdata object can't be created without an IModelMetadataProvider or an already existing ViewData Object.
I solved this issue by passing the ViewData object that is a default property on the controller through to the orchestrator and creating a new object based on that.
Full details can be found here:
https://github.com/aspnet/Mvc/issues/2814

Related

Setting the type of an object a custom binder would apply to in a vNext application?

How would you set the type of the object you want the binder to apply to e.g:
ModelBinders.Binders.Add(typeof(Person), new PersonModelBinder());
in a vNext application?
I can see that ModelBinders.Add has 3 overloads,
1) IModelBinder
2) ModelBinderDescriptor
3) Type
but I'm not sure how to translate the old code to this new code? Basically I want this kind of thing:
services.AddMvc().Configure<MvcOptions>(options =>
{
options.ModelBinders.Add(typeof(Person), new PersonModelBinder()));
});
Thanks! btw, I have looked here as well.
This seems indeed like a gap in MVC 6. For now you will have to write the code directly in your binder.
public Task<bool> BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext.ModelType == typeof(Person))
{
var value = // get the value
bindingContext.Model = value;
return Task.FromResult(true);
}
return Task.FromResult(false);
}
Here and here is a similar code used in the framework to implement [FromHeader]
Here is a link to an issue tracking bringing back a similar overload to MVC 5.

Data is not inserting to the database

I am new to asp .net MVC 4.
I have one text box and the text box value I am fetching from one table.But while clicking on submit button this value I want to insert into different table , which is not inserting and showing error.It is taking value as null.
coding
View
#Html.TextBox("empname", (string)ViewBag.empname, new { #readonly = "readonly" })
controller
[HttpGet]
public ActionResult Facilities()
{
mstEmpDetail emp = new mstEmpDetail();
emp = db.mstEmpDetails.Single(x => x.intEmpId == 10001);
ViewBag.empname = emp.txtEmpFirstName;
return View();
}
[HttpPost]
public ActionResult Facilities(TrnBusinessCardDetail bc)
{
var empname1 = ViewBag.empname;
bc.txtfirstName = empname1;
db.TrnBusinessCardDetails.Add(bc);
db.SaveChanges();
return RedirectToAction("Facilities");
}
While I was working with normal text box it was inserting properly,but when I have retrieve
fro DB then i am getting this problem ?
How to solve this problem ?
Viewbag is a one way street - you can use it to pass information to the view, but you cannot use it to get the information from the view. The statement ViewBag.empname in your POST method has a value of null in your code.
As suggested by #dotnetom, ViewBag is a one way street. MVC is stateless so a POST request is not a "Round Trip" from previous get request. Thus your ViewBag can not hold its state.
MVC can determine (and construct) your action parameters from Form Parameters. In your case you have added a textbox with name "empname". So you should get this value as parameter in your POST request.
[HttpPost]
public ActionResult Facilities(TrnBusinessCardDetail bc, string empname)
{
bc.txtfirstName = empname;
db.TrnBusinessCardDetails.Add(bc);
db.SaveChanges();
return RedirectToAction("Facilities");
}
This would be simplest of solution given your problem. More appropriate would be binding your textbox directly with you model property. This way you will not have to worry about retrieving and assigning property value to model in your controller.
I think the problem is when you are using var empname1 = ViewBag.empname; in post controller because ViewBag.empname lost its value at that time.

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[X]', but this dictionary requires a model item of type 'X'

*CORRECTION
The problem occurs when my view is called to populate a list from my user table.
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Mike.Models.User]', but this dictionary requires a model item of type 'Mike.Models.User'.
Here is my controller action:
public ActionResult Registration(Mike.Models.User user)
{
if (ModelState.IsValid)
{
using (var db = new UserContext())
{
var crypto = new SimpleCrypto.PBKDF2();
var encrypPass = crypto.Compute(user.password);
var sysUser = db.Users.Create();
sysUser.LastName = user.LastName;
sysUser.FirstName = user.FirstName;
sysUser.Email = user.Email;
sysUser.password = encrypPass;
sysUser.passwordSalt = crypto.Salt;
sysUser.UserID = user.UserID;
db.Users.Add(sysUser);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
}
return View(user);
}
Can someone please help me.... There are responses to similar questions on the internet but I believe mine is unique.. I have searched for weeks to no avail.
Thanks in advance,
Renior
Here is my simple controller action...
public ActionResult Index()
{
return View(db.Users.ToList());
}
and my razor syntax.
#model IEnumerable
Im trying to populate a view of my user table list..
In your Registration view at the top where your model declaration is, instead of this:
#model List<Mike.Models.User>
you need to have:
#model Mike.Models.User
You probably used strongly typed scaffolding feature to generate your view but instead of details option you chose a list option...
Take this at face value - yours is not unique. Your problem is you are passing an array of user to a controller action that expects a user.
You need to post your HTML but it is probably something like #model List user or something instead of a single user.
If your model represents a single user then pass that to the controller. If opposite, do opposite,
If you want to pass a list to the controller use list users
edit
make your razor syntax
#model Mike.Models.User

pass decimal to controller mvc4

I'm having issues with one of my controller actions .
I have a decimal stored in my viewbag on my view. And am attempting to pass this via and actionlink to my controller method.
ViewBag.Interest =1.25
#Html.ActionLink("Export", "ExportInterest", "Export", new {id = ViewBag.Interest}, null).
My controller method looks something like this :
public ActionResult ExportInterest(decimal? id)
{
return View();
}
I can see the 1.25 be passed via query string but I'm getting a 404 file not found when it's being routed. Note: if I change it to just a whole number with no decimal point it's working fine. Is this an encoding error ? It's not recognising the decimal point , perhaps I need to escape it ? Is there a htmlhelper I should be using? Initially I thought it might be a localisation thing but I have my globalisation culture set up in my web.config. I'm obviously doing something silly here....any help would be appreciated...
Update: I have also tried casting my viewbag to a nullable decimal in the action link but this didn't have any effect
My guess is has to do with the data type in the view bag.
I have passed decimals to controllers before so I know it can be done. But if you changed your link to be:
#Html.ActionLink("Export", "ExportInterest", "Export", new {id =1.25}, null).
Does it work?
Try that:
decimal? d = (decimal?)ViewBag.Interest;
#Html.ActionLink("Export", "ExportInterest", "Export", new {id = d}, null)
or
#Html.ActionLink("Export", "ExportInterest", "Export", new {id = (decimal?)ViewBag.Interest}, null)

MVC 4 Partial with separate Controller and View

I've developed ASP.NET Forms for some time and now am trying to learn MVC but it's not making total sense how to get it to do what I want. Perhaps I need to think about things differently. Here is what I'm trying to do with a made up example:
Goal - Use a partial file, which can be placed anywhere on the site which will accept a parameter. That parameter will be used to go to the database and pass back the resulting model to the view. The view will then display one or more of the models properties.
This isn't my code, but shows what I'm trying to do.
File: Controllers/UserController.cs
[ChildActionOnly]
public ActionResult DisplayUserName(string userId)
{
MyDataContext db = new MyDataContext()
var user = (from u in db.Users where u.UserId = userId select u).FirstOrDefault();
return PartialView(user);
}
File: Views/Shared/_DisplayUserName.cs
#model DataLibrary.Models.User
<h2>Your username is: #Model.UserName</h2>
File: Views/About/Index.cshtml
#{
ViewBag.Title = "About";
}
<h2>About</h2>
{Insert Statement Here}
I know at this point I need to render a partial called DisplayUserName, but how does it know which view to use and how do I pass my userId to the partial?
It's what I expect is a very basic question, but I'm yet to find a tutorial which covers this.
Thanks in advance for your help.
You should call Html.Action or Html.RenderAction like:
#Html.Action("DisplayUserName", "User", new {userId = "pass_user_id_from_somewhere"});
Your action should be like:
[ChildActionOnly]
public ActionResult DisplayUserName(string userId)
{
MyDataContext db = new MyDataContext()
var user = (from u in db.Users where u.UserId = userId select u).FirstOrDefault();
return PartialView("_DisplayUserName", user);
}
This should do the trick.
I always make sure to close the MyDataContext... Maybe enclose everything in a using statement... If you notice when VS does it for you they create the entity as a private variable in the Controller Class (outside of the controllers) and then close it with the dispose method... Either way I believe you need to make sure those resources are released to keep things running smooth. I know it's not in the question but I saw that it looked vulnerable.