HtmlFieldPrefix not mapping to model - c#

Hello I have recently began work on a largely JQuery/JQueryUI based ASP .Net website. The idea was to have only one page and to have the rest of the content be dynamic, etc loaded in through dialogs and ajax.
The problem is however when a Create & a Edit form for the same model are open in dialogs at the same time some JQueryUI widgets such as the DatePicker stop working as the forms cause the DOM to have duplicate id's on the fields which are present in both.
So I tried using this code on the controller:
ViewData.TemplateInfo.HtmlFieldPrefix = "Create"; // or Edit etc
This worked to fix the DatePicker problem, but the fields no longer mapped to the model when they were posted back to the controller.
Does anyone know how to fix this?

You could try specifying the same prefix when binding back:
[HttpPost]
public ActionResult Create([Bind(Prefix = "Create")] CreateViewModel model)
{
...
}

For anyone having the same issue, you could also just rename your model to "create" as shown below:
[HttpPost]
public ActionResult Create(CreateViewModel create)
{
...
}
Which I think looks nicer, but it's a bit risky. If another developer, or you, decides to change the parameter name later the form will break which is not ideal.
I figured this out as one of my forms was binding correctly and the other wasn't. One had the prefix as the parameter name and one was just "model".

Related

How to bind data in ASP.NET MVC 5 / Entity Framework?

I'm completely new to MVC, moving from Webforms which I know well.
I've got the basics and now trying to work with a database. I can send data to the view no problem but how do I get the edited back?
I'm seeing lots of examples like this:
public ActionResult Update(MyObject myObject)
{
//do database EFW here
}
I can't work out how you get the data from the web-form(view) into myObject. I'm not doing anything clever I have followed a few examples on line but none explain how this mechanism works.
For the form I'm using #Html.BeginForm and helper functions (Html.TextBoxFor) etc, to create my form fields. The problem is now I can't get the edited data back so I can update my data. I hit the right controller action.
The only thing that's different is my form a is a partial view inside a bootstrap dialog.
UPDATE
Well I finally have a object back in my action method, however it doesn't have the key field populated, only the things on the form so I still can't save it (as an update) because I don't know which one it is.
I get and send this object to the view
var diary = new mySQLEntities().Diaries.Single(d => d.DRefno == Id);
and all is good, then what I want to do is this, or something similar
public ActionResult DiaryItemUpdate(mymvc.Diary Diary)
{
mySQLEntities db = new mySQLEntities();
db.Diaries.Add(Diary);
db.SaveChanges();
return RedirectToAction("Index", "Home");
}
[Bind(Include = ... )] doesn't work, it just deletes ALL the properties, even the ones I was getting back.
All the examples I look at seem to do the same thing as I'm doing but it just doesn't work.
I thought this was going to be easy but it isn't. I looked at EF a while back and ditched it for this very reason. It says it makes development easy, it's making it a lot harder for me. I can see why I stuck with web-forms for so long.
Any properties you pass in need to be instantiated in the form if you want them passed back. You need to add the ID of the object as a hidden form element:
#Html.HiddenFor(model => model.ID)
This will ensure that the ID for the object you sent to the view gets posted back.

MVC best practice for displaying static generated data

Question background:
I have a two page MVC 4 web app. The first page's view currently has its data manually typed into the View as its static i.e nothing is being passed to the View from its associated Controller method, as shown:
Index controller method:
Public ActionResult Index()
{
return View();
}
Index.cshtml View:
<div class="titleHeader">Welcome To This Test Example</div>
Best practice:
Is the above example OK to use, or should I generate a ViewModel object on the Index controller, populate the static data then return it to the View? As Shown:
Index Controller Index method with ViewModel:
Public ActionResult Index()
{
HomePageVM homepageVM = new HomePageVM
{
WelcomeMessage = "Welcome To This Test Example";
};
return View(homepageVM);
}
Index.cshtml now bound to the HomePageVM ViewModel:
#model TestPage.Models.HomePageVM
<div class="titleHeader">#Model.WelcomeMessage</div>
I think (opinion), it's best to use Resource files for static data.
With these Resource file you will be able to easily port to a multi language website.
Basically you'll need to create resx files, make the entries public.
In your cshtml you can access it by:
<div class="titleHeader">#Resources.WelcomeMessage</div>
Depending on the UIThread's culture info it is able to select the appropriate language.
You can find a tutorial here:
http://www.codeproject.com/Articles/778040/Beginners-Tutorial-on-Globalization-and-Localizati
As for your options:
1) There is really no need to create a ViewModel for static data unless you'll expect it to be dynamic in the future (although it's bad habit to develop now for future requirements).
2) Hard coded strings in the cshtml, it possible, but not suited for multi-language. There is 1 benefit I would like to mention: it's easier for non-developers to alter the html.
Based on the principle of not gold plating your code.
You don't need the view model (right now) so don't add it. If you want a view model later then it's simple to add one. Your goal should be to create the simplest solution possible. For me that means the view model (or any other solution that's not pure HTML) only add's unnecessary complexity.
The answer from stefan about resources again seems gold plating to me. It's based on the:
will be able to easily port to a multi language website.
Is your site multi language? Is it ever likely to be? If no, this is gold-plating.
I am not really a code guru but:
Why use viewbag or even viewmodel when you just want to show one line of static text? You don't usually use calculator when you want to add 2 + 2 don't you ?
<div> seems fine to me in this one

Truncated strings with TextBoxFor

In our ASP.Net MVC 3 application we're getting truncated strings on our forms when the string value contains a double-quote.
For example, given a textbox:
#Html.TextBoxFor(m => m.County)
If the user enters the string: 'Hampshire"County', when rendering the value back out to the form, only the string 'Hampsire' is displayed. If I inspect the value in the model, the double-quote is escaped as 'Hampshire\"County'. In Fiddler, the posted value is correct and the value is stored in the database correctly, so it would appear to be related to the Html helper that renders the textbox out to the client.
Can anyone shed some light on this?
I was unabled to reproduce this issue. Just created a new MVC 3 project, created a controller with 2 actions (GET and POST), with a typed view, receiving an object with a string property Text, and displaying it inside a form... It all proceeds as expected. No issues. Everything I type in, is posted, and comes back correctly in the POST.
View
#model MvcApplication1.Models.MyClass
#{
ViewBag.Title = "Home";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Home</h2>
#using (Html.BeginForm())
{
#Html.TextBoxFor(m => m.Text)
}
Controller
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyClass data)
{
return View(data);
}
}
Model
public class MyClass
{
public string Text { get; set; }
}
So, the problem must be somewhere else... with something that can mess with the value being rendered (editor templates, javascript)
Try looking at the source of the rendered page to see if the value there is correct, if it is, then it must be javascript, otherwise, it must be something in the server.
As it turns out this was a problem of our own making. It turns out some bright spark (me) about 9 months ago thought it would be a good idea to override the HtmlAttributeEncode() method in a custom HttpEncoder. This fires during output rendering.
The reason I added this was that parts of the application need to render script blocks to the client, and the default encoder was screwing with the JS code in the HTML.
When we removed the overriding method, the problem went away. Lesson learned: don't screw around with the framework unless you absolutely need to.
Once again, thanks all for taking the time to consider this.

The model item passed into the dictionary is of type 'System.Guid', but this dictionary requires a model item of type 'System.String'

I've looked through so many similar questions here, but none were able to solve our problem or explain why this might be happening.
We created an EDMX from an existing database, and used MVC 4 scaffolding to automatically generate the controller and views for us. The Index page is fine, but when we choose an entity to Edit, this error is thrown. There are no custom editors in our solution, nor is this a partial page update.
The controller code for the edit page is this:
public ActionResult Edit(int id = 0)
{
MessageProfile messageprofile = db.MessageProfiles.Find(id);
if (messageprofile == null)
{
return HttpNotFound();
}
return View(messageprofile);
}
The model declaration on Edit.cshtml is
#model Web.UI.Areas.Admin.Models.MessageProfile
and the error is thrown at
#Html.EditorFor(model => model.APIKey)
The EDMX has APIKey as a GUID, the generated model class has APIKey as a model, and the EditorFor indicates it's an editor for a GUID when we hover over it in the code. We are completely stumped where a String is entering the process. Appreciate any help.
Having workd with ASP.NET Dynamic Data quite often, my expectation was that there would be an editor already present for every primitive type in MVC scaffolding. There is not, and attempts are made to do an implicit conversion. When that fails, this error usually gets thrown.
In this case, the easy solution was to use Html.TextBoxFor instead of Html.EditorFor. It's a weird case, but the value is being pasted in from an email. In other cases, we made the form better with a lookup and dropdownlist.
Had we wanted to have a GUID-specific editor, we would have had to create our own. All we would have ended up with was a textbox anyway, so that's why the first solution was the simplest.
This happened to me as well. The problem for me was that I created custom Editfor templates and I did not include one for System.Guid. Since it could find one to match system.Guid it would try to use System. String thus generating that error.
If this is the case in your EditorTemplates folder add a cshtml called Guid, then add the following:
#model System.Guid
#Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue)

ASP.NET MVC3 - How to serve View() from another controller

So in order accomplish what I asked in this post I did the following:
[iPhone]
[ActionName("Index")]
public ActionResult IndexIPhone()
{
return new Test.Areas.Mobile.Controllers.HomeController().Index();
}
[ActionName("Index")]
public ActionResult Index()
{
return View();
}
Which still serves the same view as the Index action method in this controller. Even though I can see it executing the Test.Areas.Mobile.Controllers.HomeController().Index() action method just fine. What's going on here? And how do I serve the Index view from Mobile area without changing the request URL (as asked in the original post referenced above)?
You have a few options:
Redirect to the Action you'd like to return: return RedirectToAction("Action-I-Want").
Return the View by name: return View("The-View-I-Want").
Note that with the 2nd approach you'd have to put your view in the "Shared" folder for all controllers to be able to find it and return it. This can get messy if you end up putting all your views there.
As a side note: The reason your work doesn't find the view is because default view engine looks for the view in the folder that "belongs" to the current executing controller context, regardless of what code you're calling.
Edit:
It is possible to group all "mobile" views in the same folder. On your Global.asax (or where ever you're setting up your ViewEngine, just add the path to your mobile View in the AreaViewLocationFormats. Mind you, you'll still have to name your views differently.
You can also write your own view engine. I'd do something like detecting the browser and then serving the right file. You could setup a convention like View.aspx, and View.m.aspx.
Anyhow, just take a look at WebFormViewEngine and you'll figure out what works best for you.
The easiest way to send a request to a view handled by another controller is RedirectToAction("View-Name", "Controller-Name").
There are overloads of View() that take route information that might work as well, but they'd require more effort to set up.
Well actually the easiest way is to make one version of your site programmed on standards instead of browser detection :D -- however in direct response to accomplish what it in a more of a ASP.NET mvc fashion, using:
RedirectToAction("ViewName", "ControllerName");
is a good method however I have found it is more practical if you feel you must program for different browser standards to create a primary view and an alternate "mobile" view under your controllers views. Then instead of writing special code on every controller, instead extend the controller like so.
public class ControllerExtended : Controller
{
private bool IsMobile = false;
private void DetectMobileDevices(){ .... }
}
Then modify your controller classes to instead say ControllerExtended classes and just add the one line to the top of each Action that you have alternate views of like so:
public class ApplicationsController : ControllerExtended
{
// GET: /Applications/Index
public ActionResult Index() {
this.DetectMobileDevices();
if(this.IsMobile){
return RedirectToAction("MobileIndex");
} else {
// actual action code goes here
return View();
}
}
}
Alternately you can use return View("ViewName"); but from my experience you want to actually perform different actions as opposed to just showing the result in a different view as in the case of presenting an HTML table as opposed to a Flex table to help iPhone users since there is no flash support in the iPhone, etc. (as of this writing)

Categories