I have encountered a problem while upgrading to MVC4 and I was wondering if anyone else has seen this problem and how to get around it. Whenever I put a IDictionary, Dictionary or RouteValueDictionary to the parameter list of an action, the route values for that MVC call are being passed.
To reproduce this problem create an MVC4 web project using the default Internet Application settings and add
IDictionary<string, object> myDictionary = null
to the parameter list of the Index controller and put a breakpoint inside the method. You will see that the IDictionary parameter is populated by the model binder with the route values.
How do I turn this off, or get around this?
It looks like after looking through bug reports for MVC4 the following issue is being tracked with the Dictionary<> model binder.
http://aspnetwebstack.codeplex.com/workitem/373
The workaround seems to be to remove the Dictionary from the parameters list and do the following:
[HttpPost]
public void Index(FormCollection form)
{
var values = new Dictionary<string, object>();
this.UpdateModel(values, "values");
}
Hopefully this helps someone else. Now if they would just fix it. Does anyone have a better work around?
Related
In our ASP.NET Core web app, I need to be able to access HttpContext.Session within a Custom RequestCultureProvider I've written. There is alot of background here... To be brief, I'll just mention that the business requirement is that I'm trying to meet, is to be able to display data in at least two different cultures, in our web app. A user may navigate to one page, where it should display in fr-FR and navigate to another page where it should display in zh-CN.
I have all of this working, when it comes to the "Response" from the server. By using an ActionFilter on a per-Action basis I can set the current thread's culture to whatever I want. We look up the various cultures from a database and store them in Session and then n the ActionFilter, based on an argument I pass to the ActionFilter method... I can even load ViewComponents via Controller Actions in the various cultures and have each view component display with a different culture setting. Given this, you can see why I can't store session in a Cookie or use the Querystring.
But the PROBLEM comes into play with "Requests" to the server, like when I edit Form data in a view and Submit/post the data back to an Action.
When I do that, my Dates are sent back in as NULL. BTW, I do Model binding and I have my dates marked with this attributes in my ViewModels:
[DataType(DataType.Date)]
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd-MMM-yyyy}")]
According to the well written article below, the order in which the Request culture is looked up, is:
https://www.jerriepelser.com/blog/how-aspnet5-determines-culture-info-for-localization/
From the query string
From a cookie
From the Accept-Language HTTP header
From the DefaultRequestCulture property of the RequestLocalizationOptions class
From the thread culture
I can certainly verify the above. If I use a cookie, it works. If I add French fr-FR as the first language in Chrome Settings, it works. If I change my default request culture in my Startup localization to fr-FR, it works...
For example, in the web page a Kendo DatePicker (or even an tag) will contain a French date like "14-août-2019", yet when I post it back to an Action, it is NULL unless I've set the querystring, cookie, Accept-Language or DefaultRequestCulture to fr-FR.
One odd thing is that #5 says it should use the current Thread Culture, and in my Action that I post Form data to I check the current thread's culture, and it is indeed fr-FR, so I don't know why my french dates are not being recognized...
So what I tried to get around this was to clear out all of those default providers and write a custom provider.
In Startup.ConfigureServices, I now do this:
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr-FR"),
new CultureInfo("zh-CN"),
new CultureInfo("en-IE"),
};
var defaultCultureSettingOverride = this.Configuration.GetSection("appsettings").GetValue<string>("DefaultCultureOverride");
defaultCultureSettingOverride = defaultCultureSettingOverride == null ? "en-US" : defaultCultureSettingOverride;
options.DefaultRequestCulture = new RequestCulture(defaultCultureSettingOverride);
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Clear();
options.RequestCultureProviders.Insert(0, new MyCustomRequestCultureProvider()
{
Options = options,
});
});
And that works too, as long as my MyCustomRequestCultureProvider returns the correct culture!
My problem now is: I NEED to be able to access Session state in my custom RequestCultureProvider. But the HttpContext sent into DetermineProviderCultureResult has a null Session. Why? Is it the wrong place in the pipeline?
And when I call options.RequestCultureProviders.Insert(0, , new MyCustomRequestCultureProvider() in ConfigureServices, I don't have access yet (as far as I can tell) to the HttpContextAccessor.
If I pass new MyCustomRequestCultureProvider(new HttpContextAccessor()), that does me no good...
And while I have access to IHttpContextAccessor accessor as a parameter passed into Startup.Configure, I can't do the same thing with Startup.ConfigureServices. If I add (IHttpContextAccessor accessor) as an additional parameter to ConfigureServices, .NET Core errors when I run it, telling me that method can only access an IServicesCollection parameter.
I'm at a dead end...
Well, Session being NULL in my custom RequestCultureProvider was my fault.
In Startup.Configure, we had app.UseSession() AFTER app.UseRequestLocalization()
Once I moved app.UseSession() BEFORE app.UseRequestLocalization(), I was able to access Session in my custom RequestCultureProvider.
And now once I get the user's culture from Session and use it to return the proper ProviderCultureResult, my form posts do contain the dates.
Been wrapped around the axle on this one, while there are some questions that are close, they either are different enough (addressing multi-tenancy, URL rewriting, etc), or are not answered. I would like to create a custom route in ASP.Net Core that takes the subdomain (if any) and passes it to the controller as a parameter.
The closest thing I found was (here), but I couldn't make it work, not sure what needs to be passed into a constructor that isn't described, but seems to be needed by the base MvcRouteHandler class.
For example, since a normal route might look like this:
http://www.example.com/home/index/3
Goes to the controller as
public class HomeController : Controller
{
public ActionResult Index(string id)
{
...
}
}
I would like to create a custom route that takes a URL like
http://somesubdomain.example.com/home/index/3
and turn it into
public class HomeController : Controller
{
public ActionResult Index(string subdomain, string id)
{
// "somesubdomain" is passed into the subdomain parameter.
...
}
}
Thanks, I've dug through more routing stuff than I know what to do with and custom routing is still pretty opaque to me. Thanks!
EDIT: I know that in each call I can probably look at the request, but that doesn't seem like the right thing to do. That's my fallback, though...
ANOTHER EDIT: Here's another example of what I want to do, only not in Core. I'm trying to figure out how to make this 'Core'.
I am working on MVC and i started learning Umbraco, I didn't get how to bind the umbraco page with mvc controller get method to show the database values. can anyone suggest any url or video?
Thansk...
What you're looking for is Umbraco route hijacking.
You can read about it here.
https://our.umbraco.org/documentation/reference/routing/custom-controllers
It's easiest to demonstrate with an example : let's say you have a Document Type called 'Home'. You can create a custom locally declared controller in your MVC web project called 'HomeController' and ensure that it inherits from Umbraco.Web.Mvc.RenderMvcController and now all pages that are of document type 'Home' will be routed through your custom controller! Pretty easy right :-) OK so let's see how we can extend this concept. In order for you to run some code in your controller you'll need to override the Index Action.
So, basically, you "simply" need to create a controller named after your document type, so for example, a document type with the name "TextPage" would need a controller called "TextPageController". Now, if you read through the documentation, you'll find that your "TextPageController" will need to inherit from the RenderMvcController. Here's an example how to achieve this.
public class TextPageController : RenderMvcController
{
public ActionResult Index()
{
return View("~/Views/TextPage.cshtml");
}
}
This forum link may help you:
https://our.umbraco.org/forum/developers/razor/38242-Umbraco-MVC4111-Surface-controller-using-an-AJAX-form
I am quite new to this Umbraco MVC.
I need to pass some data bound to a model to my partial view from the GET action method.
This simply is not working in a regular MVC way.
[httpget]
public ActionResult Membership()
{
SupplierMembershipInfoModel mm = new SupplierMembershipInfoModel();
mm.ProductPackage = "sssssssss";
ViewBag.status = Request.QueryString["status"];
return PartialView("MembershipPartial", mm);
}
my view:
#model Umbraco.Web.Models.SupplierMembershipInfoModel
some html.....
<td>#Model.ProductPackage</td>
I don't get data here...and the debug never hits the action. But it hits any POST action method.
I know i am doing something wrong...but just don't know what the mistake is??
Any ideas??
As #Sebastiaan points out, the best place to start is the Umbraco community site. There is documentation specific to your issue here: http://our.umbraco.org/documentation/Reference/Templating/Mvc/child-actions
In a nutshell, you want to display a child action on your page and Umbraco uses SurfaceControllers for this. A SurfaceController is simply a Controller that inherits from Umbraco.Web.Mvc.SurfaceController. This provides you Controller with access to the Umbraco context - see here (http://our.umbraco.org/documentation/Reference/Templating/Mvc/surface-controllers).
Either way, you should read the whole documentation section on templating as it will give you a lot of insight into how Umbraco MVC is managed.
I recently installed ASP.NET MVC 3 via web platform installer. I don't have the intellisense support for ViewBag in Razor view. Intellisense works fine with model in Razor view. I tried to rebuild solution, disable ReSharper... but I couldn't get it to work.
Any help would be greatly appreciated.
The ViewBag property is typed as dynamic, which means that there is no IntelliSense.
ViewBag is an alias/alternative syntax for accessing the ViewData dictionary. The two following lines of code are equivalent:
ViewBag.Message = "My message";
ViewData["Message"] = "My message";
ViewBag offers a slightly terser syntax than ViewData. Also notice that accessing ViewData using string keys also provides no IntelliSense, so you don't really lose any functionality.
One last note is that ViewBag and ViewData use the same backing storage, so that setting a property using one method makes it available using the other method:
ViewBag.Message = "My message";
string message = ViewData["Message"];
// message is now "My message"
Adding to marcind's answer of the ViewBag being dynamic:
If you want intellisense, then you're going to have to pass in a strongly typed object and then in your view, you can set:#model Namespace.YourModel which will give you intellisense when you try to do #Model.Property