What is IViewLocationExpander.PopulateValues() for in Asp.Net Core MVC - asp.net-core-mvc

I'm using ASP.NET MVC CORE. I have implemented my own ViewLocationExpander so that I can structure my project the way I want and place my views where I like.
This is accomplished by implementing a class that inherits from IViewLocationExpander and most of the work occurs in the following method:
ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
Everything is working pretty sweet but the interface defines a 2nd method that I don't know how to properly implement:
PopulateValues(ViewLocationExpanderContext context)
I've read articles all over the internet about this interface but no one has really provided much info on what exactly this method is for other than saying vague things about how it helps with caching.
I'd really appreciate it if someone could explain how this method is used by the framework and how I can use it appropriately to aid caching if that is indeed what it is for.

Maybe the following additional info taken directly from a GitHub MVC issue can answer your question:
Caching includes the Values dictionary in its lookup. Unless the PopulateValues() method adds distinct information to ViewLocationExpanderContext.Values, the ExpandViewLocations() method will be called just once per original file name i.e. the initial information is cached from then on.
On top of that, the particular example posed by OP can help understand even better, at least that's what happened to me:
His project has views with the same name under two different directory
trees (say Foo and Bar)
Depending on some data extracted by current action context, the view to locate should be under either one of those trees
Without any code in PopulateValues(), view engine will ask once to locate the view, then use view "standard" data (e.g. ControllerName, ActionName, Area, etc.) in order to cache the actual location where view is found.
So, in OP case, once a view location is cached (say e.g. from Foo directory tree) everytime a view with same name is needed it will always be from that tree, there'll be no way to detect if the one in the other Bar tree should have been actually picked up.
The only way for OP is to customize PopulateValues() by adding specific, distinctive view details to Values dictionary: in current scenario, those are the info extracted from current action context.
That additional info are used two-fold: ExpandViewLocations() might use them when invoked in order to determine proper location, while view engine will use them to cache view location once found.
Dec. 2021 update
Official doc page is more descriptive. From Remarks section:
Individual IViewLocationExpanders are invoked in two steps:
(1) PopulateValues(ViewLocationExpanderContext) is invoked and each expander adds values that it would later consume as part of ExpandViewLocations(ViewLocationExpanderContext, IEnumerable<String>). The populated values are used to determine a cache key - if all values are identical to the last time PopulateValues(ViewLocationExpanderContext) was invoked, the cached result is used as the view location.
(2) If no result was found in the cache or if a view was not found at the cached location, ExpandViewLocations(ViewLocationExpanderContext, IEnumerable<String>) is invoked to determine all potential paths for a view.

Haven't messed around with it enough to be able to give you a concrete answer, but have a look at IViewLocationExpander.PopulateValues(ViewLocationExpanderContext context) on the ASP.NET MVC GitHub repo:
public interface IViewLocationExpander
{
/// <summary>
/// Invoked by a <see cref="RazorViewEngine"/> to determine the values that would be consumed by this instance
/// of <see cref="IViewLocationExpander"/>. The calculated values are used to determine if the view location
/// has changed since the last time it was located.
/// </summary>
/// <param name="context">The <see cref="ViewLocationExpanderContext"/> for the current view location
/// expansion operation.</param>
void PopulateValues(ViewLocationExpanderContext context);
// ...other method declarations omitted for brevity
}
Readability format:
"Invoked by a RazorViewEngine to determine the values that would be consumed by this instance of IViewLocationExpander. The calculated values are used to determine if the view location has changed since the last time it was located.
Parameters:
context: The ViewLocationExpanderContext for the current view location expansion operation."
I've had a look at some classes which implement this interface - some declare the method but leave it empty, others implement it.
NonMainPageViewLocationExpander.cs:
public void PopulateValues(ViewLocationExpanderContext context)
{
}
LanguageViewLocationExpander.cs:
private const string ValueKey = "language";
public void PopulateValues(ViewLocationExpanderContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// Using CurrentUICulture so it loads the locale specific resources for the views.
#if NET451
context.Values[ValueKey] = Thread.CurrentThread.CurrentUICulture.Name;
#else
context.Values[ValueKey] = CultureInfo.CurrentUICulture.Name;
#endif
}
The article "View Location Expander in ASP.NET Core and MVC 6" provides an example. Here's an excerpt of the explanation:
You can add as many view location expanders as you want. IViewLocationExpander interface has 2 methods, PopulateValues and ExpandViewLocations. PopulateValues method allows you to add values that can be later consumed by ExpandViewLocations method. The values you put in PopulateValues method will be used to find cache key. ExpandViewLocations method will be only invoked if there is no cache result for the cache key or when framework is unable to find the view at the cached result. In the ExpandViewLocations method, you can return your dynamic view locations. Now you can register this view location expander in Startup.cs file,
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new MyViewLocationExpander());
});

Basically the method can populate values into context.Values that will later be used to determine if a cached list should be used or if the ExpandViewLocations will be called....

Related

Is it bad to use ViewModelLocator to Grab other VM's for use in another Vm?

I am using MVVM light and figured out since that the ViewModelLocator can be used to grab any view model and thus I can use it to grab values.
I been doing something like this
public class ViewModel1
{
public ViewModel1()
{
var vm2 = new ViewModelLocator().ViewModel2;
string name = vm2.Name;
}
}
This way if I need to go between views I can easily get other values. I am not sure if this would be best practice though(it seems so convenient makes me wonder if it is bad practice lol) as I know there is some messenger class thing and not sue if that is the way I should be doing it.
Edit
static ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<ViewModel1>();
SimpleIoc.Default.Register<ViewModel2>();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public ViewModel1 ViewModel1
{
get
{
return ServiceLocator.Current.GetInstance<ViewModel1 >();
}
}
Edit
Here is a scenario that I am trying to solve.
I have a view that you add price and store name to. When you click on the textbox for store name you are transferred to another view. This view has a textbox that you type the store you are looking for, as you type a select list get populated with all the possible matches and information about that store.
The user then chooses the store they want. They are transferred back to the view where they "add the price", now the store name is filled in also.
If they hit "add" button it takes the price, the store name, and the barcode(this came from the view BEFORE "add price view") and sends to a server.
So as you can see I need data from different views.
I'm trying to understand what your scenario is. In the MVVMlight forum, you added the following context to this question:
"I have some data that needs to be passed to multiple screens and possibly back again."
For passing data between VMs, I would also - as Matt above - use the Messenger class of MVVMLight as long as it is "fire and forget". But it is the "possibly back again" comment that sounds tricky.
I can imagine some scenarios where this can be needed. Eg. a wizard interface. In such a case I would model the data that the wizard is responsible for collecting and then bind all Views to the same VM, representing that model object.
But that's just one case.
So maybe if you could provide a little more context, I would be happy to try and help.
Yes, you can do this, in as much as the code will work but there is a big potential issue you may run into in the future.
One of the strong arguments for using the MVVM pattern is that it makes it easier to write code that can be easily tested.
With you're above code you can't test ViewModel1 without also having ViewModelLocator and ViewModel2. May be that's not too much of a bad thing in and of itself but you've set a precedent that this type of strong coupling of classes is acceptable. What happens, in the future, when you
From a testing perspective you would probably benefit from being able to inject your dependencies. This means passing, to the constructor--typically, the external objects of information you need.
This could mean you have a constructor like this:
public ViewModel1(string vm2Name)
{
string name = vm2Name;
}
that you call like this:
var vm1 = new ViewModel1(ViewModelLocator.ViewModel2.name);
There are few other issues you may want to consider also.
You're also creating a new ViewModelLocator to access one of it's properties. You probably already have an instance of the locator defined at the application level. You're creating more work for yourself (and the processor) if you're newing up additional, unnecessary instances.
Do you really need a complete instance of ViewModel2 if all you need is the name? Avoid creating and passing more than you need to.
Update
If you capture the store in the first view/vm then why not pass that (ID &/or Name) to the second VM from the second view? The second VM can then send that to the server with the data captured in the second view.
Another approach may be to just use one viewmodel for both views. This may make your whole problem go away.
If you have properties in 1 view or view model that need to be accessed by a second (or additional) views or view models, I'd recommend creating a new class to store these shared properties and then injecting this class into each view model (or accessing it via the locator). See my answer here... Two views - one ViewModel
Here is some sample code still using the SimpleIoc
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<IMyClass, MyClass>();
}
public IMyClass MyClassInstance
{
get{ return ServiceLocator.Current.GetInstance<IMyClass>();}
}
Here is a review of SimpleIOC - how to use MVVMLight SimpleIoc?
However, as I mentioned in my comments, I changed to use the Autofac container so that my supporting/shared classes could be injected into multiple view models. This way I did not need to instantiate the Locator to access the shared class. I believe this is a cleaner solution.
This is how I registered MyClass and ViewModels with the Autofac container-
var builder = new ContainerBuilder();
var myClass = new MyClass();
builder.RegisterInstance(myClass);
builder.RegisterType<ViewModel1>();
builder.RegisterType<ViewModel2>();
_container = builder.Build();
ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(_container));
Then each ViewModel (ViewModel1, ViewModel2) that require an instance of MyClass just add that as a constructor parameter as I linked initially.
MyClass will implement PropertyChanged as necessary for its properties.
Ok, my shot at an answer for your original question first is: Yes, I think it is bad to access one VM from another VM, at least in the way it is done in the code example of this question. For the same reasons that Matt is getting at - maintainability and testability. By "newing up" another ViewModelLocator in this way you hardcode a dependency into your view model.
So one way to avoid that is to consider Dependency Injection. This will make your dependencies explicit while keeping things testable. Another option is to use the Messenger class of MVVMLight that you also mention.
In order to write maintainable and testable code in the context of MVVM, ViewModels should be as loosely coupled as possible. This is where the Messenger of MVVMLight can help. Here's a quote from Laurent on what Messenger class was intended for:
I use it where decoupled communication must take place. Typically I use it between VM and view, and between VM and VM. Strictly speaking you can use it in multiple places, but I always recommend people to be careful with it. It is a powerful tool, but because of the very loose coupling, it is easy to lose the overview on what you are doing. Use it where it makes sense, but don't replace all your events and commands with messages.
So, to answer the more specific scenario you mention, where one view pops up another "store selection" view and the latter must set the current store when returning back to the first view, this is one way to do it (the "Messenger way"):
1) On the first view, use EventToCommand from MVVMLight on the TextBox in the first view to bind the desired event (eg. GotFocus) to a command exposed by the view model. Could be eg. named OpenStoreSelectorCommand.
2) The OpenStoreSelectorCommand uses the Messenger to send a message, requesting that the Store Selector dialog should be opened. The StoreSelectorView (the pop-up view) subscribes to this message (registers with the Messenger for that type of message) and opens the dialog.
3) When the view closes with a new store selected, it uses the Messenger once again to publish a message that the current store has changed. The main view model subscribes to this message and can take whatever action it needs when it receives the message. Eg. update a CurrentStore property, which is bound to a field on the main view.
You may argue that this is a lot of messaging back and forth, but it keeps the view models and views decoupled and does not require a lot code.
That's one approach. That may be "old style" as Matt is hinting, but it will work, and is better than creating hard dependencies.
A service-based approach:
For a more service-based approach take a look at this recent MSDN Magazine article, written by the inventor of MVVMLight. It gives code examples of both approaches: The Messenger approach and a DialogService-based approach. It does not, however, go into details on how you get values back from a dialog window.
That issue is tackled, without relying on the Messenger, in this article. Note the IModalDialogService interface:
public interface IModalDialogService
{
void ShowDialog<TViewModel>(IModalWindow view, TViewModel viewModel, Action<TViewModel> onDialogClose);
void ShowDialog<TDialogViewModel>(IModalWindow view, TDialogViewModel viewModel);
}
The first overload has an Action delegate parameter that is attached as the event handler for the Close event of the dialog. The parameter TViewModel for the delegate is set as the DataContext of the dialog window. The end result is that the view model that caused the dialog to be shown initially, can access the view model of the (updated) dialog when the dialog closes.
I hope that helps you further!

Strongly typed ViewData for complex object persistence

I'm working on a ASP.NET MVC system where you may click on a ajax link that will open a window (kendo window but it does not affect the situation) which a complex flow. To make this less of a nightmare to manage, I made a ViewModel (as I should) but this ViewModel is a complex object due to the complexity of the procedure.
There is anywhere from a single to 5 windows that asks various questions depending on a lot of conditions (including, but not limited to, what time you click the link, who you are, what schedule is attached to your account and, obviously, your previous answers in this flow).
The problem is that having a complex object, I cannot simply make #Html.HiddenFor(o=>o.XXX). So I proceeded to find an alternative and it led me with a single option, TempData. I'm really not a fan of dynamics and object types. I'd really like to have this View Model strongly typed.
What would be the best way to approach this?
Here is a case where using Session or TempData might make sense. Contrary to popular belief, you can make these somewhat strongly-typed. Not like a viewmodel, but you can avoid keychain messes by using extension methods.
For example, instead of doing something like this:
TempData["NestedVariable1"] = someObject;
...
var someObject = TempData["NestedVariable1"] as CustomType;
You can write extension methods to store these variables, and encapsulate the keys and casting in the extension methods.
public static class ComplexFlowExtensions
{
private static string Nv1Key = "temp_data_key";
public static void NestedVariable1(this TempData tempData, CustomType value)
{
// write the value to temp data
tempData[Nv1Key] = value;
}
public static CustomType NestedVariable1(this TempData tempData)
{
// read the value from temp data
return tempData[Nv1Key] as CustomType;
}
}
You can then read / write these values from either controllers or views like this:
TempData.NestedVariable1(someObject);
...
var someObject = TempData.NestedVariable1();
You could use the same pattern with Session as well. And instead of saving each individual scalar value in a separate variable, you should be able to store an entire nested object graph in the variable. Either that, or serialize it to JSON and store that, then deserialize when you get it back out. Either way, I think this beats a ton of hidden fields written out to your view's form.

Entity Framework in detached mode with MVC application

I have started working out with Entity Framework (EF) for an MVC n-tier application. It would seem that very obvious that this being a web application (which is stateless), I would have to use detached object models. There is no ambiguity with doing an Add operation. However when doing an edit there are here are two ways
Fetch the original object in context, attach the updated object and
then save to database. Something like mentioned in answer to this
question
EF4 Context.ApplyCurrentValues does not update current values
Set individual modified properties explicitly using the IsModified property of individual fields of the object like
mentioned in this article
http://msdn.microsoft.com/en-us/data/jj592677.aspx
Method 1 has disadvantage of having to load object into memory from database each time an update needs to be performed.
Method 2 would require having to manually pass which fields to be set as IsModified to true from wherever the object an be updated. So for e.g. for each object, I may need to create a boolean collection object for each field of the object.
e.g.
SaveEntity(EntityClass e, EntityStateClass ec)
{
context.Entry(e).Property("Name").IsModified = ec.NameState;
context.SaveChanges();
}
class EntityStateClass{ public bool NameState;}
I would prefer method 2 simply for the sake of performance but I am hindered by the n-tier architecture and repository pattern I am using. My Repository interface restricts save method for any object to be
SaveEntity(EntityClass e);
So I cannot pass the "state" object. Context class is not available and should not be available outside DAL. So I cannot set property outside. Is there any "proper" way to achieve this ?
Note: Self-Tracking Entity is also out of question since I cannot send entities with state to client (the browser) since I am intent on keeping the html lightweight.
EDIT: After a lot of thinking, I am trying to use following mechanism to keep track of modified state for each field in my domain class
Declare a partial class for entity class.
For each field that is updateable, declare a boolean property like "IsModified_FieldName"
Set the "IsModified_FieldName" property when the field is set.
However for this I need Entity Framework to generate explicit properties for me instead of implicit properties that it auto-generates. Does EF provide an handle to do this ?
Here is sample code of what I am trying to achieve
//Save Method for class EntityClass.
SaveEntity(EntityClass e)
{
context.Entry(e).Property("Name").IsModified = e.IsModified_Name;
context.SaveChanges();
}
//EntityClass is class autogenerated by EF
public partial class EntityClass
{
//This is auto-generated property by EF
public string Name {get; set;}
/* This is what I would like EF to do
private string name;
public string Name
{
get {return Name;}
set {
name = value;
//this is what I would like to do
this.IsModified_Name = true;
};
}
*/
}
//This is another partial definition for EntityClass that I will provide
public partial class EntityClass
{
//This property will be set to true if "Name" is set
public bool IsModified_Name {get; set;}
}
PS: It seems the information I have provided is not sufficient and therefore there are no responses.
I am using DbContext (Database first model)
EF auto-generates the class files for me. So each time I update my database, the class files are regenerated.
To your concrete question: The entities are generated by a T4 template and it should be possible to modify this template (which is in text format) to generate the entities in a way you want to shape them.
But I have a few remarks about your concept:
In a web application data are usually changed by a user in a browser. To have a definite knowledge what really has been changed you need to track the changes in the browser (probably by some Javascript that sets flags in the data (a ViewModel for example) when a user edits a text box for instance).
If you don't track the changes in the browser what happens? The data get posted back to the server and you don't know at the server side (with MVC in a controller) which property has been changed. So, your only chance is to map all properties that has been posted back to your EntityClass and every property will be marked as Modified, no matter if the user really did a change or not. When you later call SaveChanges EF will write an UPDATE statement that involves all those properties and you have an unnecessary overhead that you you want to avoid.
So, what did you win by setting individual properties instead of setting the whole entity's state to Modified? In both cases you have marked all properties as Modified. Exceptions are partial changes of an entity, for example: You have a Customer entity that has a Name and City property and a view that only allows to edit the Name but not the City and a corresponding ViewModel that only contains a Name property. In this case your procedure would only mark the Name property of the Customer entity as Modified but not the City. You might save here a little bit because you don't save the City property value to the database. But you still save the Name even if it didn't change.
If you use solution 1 (ApplyCurrentValues) you have to load the entity first from the database, yes, but it would only mark the properties as Modified that really changed compared to their values in the database. If the user didn't change anything no UPDATE would be written at all.
Keep in mind that you are only at the beginning to implement your concept. There are other changes to the data that can happen in the browser than only scalar property changes, namely relationship changes. For example a user changes the relationship from an Order to a Customer or you have a view that has an Order and a collection of OrderItems and the user cannot only edit the Order header but also edit the OrderItems and remove and add new OrderItems. How do you want to recognize when the data come back from the browser to the server which collection item has been added and which has been removed - unless you track all those changes in the browser and send tracking information back to the server in addition to the actual data or unless you reload the Order and OrderItems from the database and merge the changes into the original entities from the database?
Personally I would vote for option 1 for these reasons:
You can use real POCOs that don't carry additional tracking information. (BTW: I have some doubt if you aren't reinventing the wheel by implementing your own tracking that EF change tracking proxies provide out of the box.)
You don't need to track changes in the browser which can become quite complex and will require Javascript in every Edit view to write change flags into hidden form fields or something.
You can use standard features of EF without having to implement your own tracking.
You are required to load entities from the database when you want to update an entity, that's true. But is this the real performance bottleneck in a web application where data have to run through the wire back and forth (and reflection (which isn't really known as to be fast) is involved by the model binder)? I have nothing said if your database is remote from the web server and connected by a 9600 baud modem. But otherwise, your plan is not only premature optimization, it is kind of premature architecture. You are starting to build a potentially complex architecture based on "it could be slow" to solve a performance problem that you actually don't know of whether it really exists.

Problems deserializing Dictionarys in MVC 3 for AJAX request (an approach that works out of the box with classic ASP.NET Webforms)

I've been successfully WebForms for AJAX calls with relatively complex set of parameters (called using jQuery.ajax). We're attempting to try using the same approach in MVC 3 but seem to be falling at the first hurdle with MVC failing to deserialize Dictionary arrays successfully.
The approach that works without issue in ASP.NET WebForms "classic" is below:
[WebMethod]
public static JQGrid.JQGridData GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder,
Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns)
And below is the MVC 3 equivalent: (nb exactly the same name/parameters - different return type but I don't think that is relevant)
[HttpPost]
public JSONResult GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder,
Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns)
With the WebMethod all the data deserializes perfectly. However, when the MVC method is called all the simple parameters deserialize fine but for some unknown reason the array of Dictionary's arrives as an array of nulls.
So, off the back of that a number of questions:
Has anyone else experienced problems with MVC 3 deserialization of arrays of dictionaries?
Does MVC 3 by default not use System.Web.Script.Serialization.JavaScriptSerializer which is I think what ASP.NET WebMethods use under the bonnet?
Can I force MVC 3 to use System.Web.Script.Serialization.JavaScriptSerializer instead of what it is using?
Or am I missing something / should my approach be slightly different? Please note that at least for now we'll need to share the client side code between classic ASP.NET WebMethods and MVC 3 and so we want that to remain as is if possible.
Finally, I can see there is a possible workaround that could be used looking at this question: POST json dictionary . Is this workaround the only game in town or have things improved since this question was posed?
jQuery AJAX call:
$.ajax(_oJQGProperties.sURL, //URL of WebService/PageMethod used
{
data: JSON.stringify(oPostData),
type: "POST",
contentType: "application/json",
complete: DataCallback
});
Example JSON.stringify(oPostData):
{
"dSearchOptions":{},
"aOriginalColumnDefinition":
[
{"name":"ID","sortable":false,"hidedlg":true,"align":"right","title":false,"width":40},
{"name":"URL","sortable":false,"hidedlg":true,"align":"left","title":false,"width":250,"link":"javascript:DoSummat(this,'{0}');","textfield":"Name"},
{"name":"Description","sortable":false,"hidedlg":true,"align":"left","title":false,"width":620}
],
"aExtraDataColumns":["Name"],
"_search":false,
"iPageSize":-1,
"iPage":1,
"sSortField":"",
"sSortOrder":"",
"iMaxRecords":0
}
I don't have any experience with binding to a dictionary array, but one possible solution is to use a custom model binder. Scott Hanselman has a blog post on this subject that you might find useful: Splitting DateTime - Unit Testing ASP.NET MVC Custom Model.
Long time getting to update this but I thought I'd share where we got to. The problem turned out to be a bug - details of which can be found here:
Bug:
http://connect.microsoft.com/VisualStudio/feedback/details/636647/make-jsonvalueproviderfactory-work-with-dictionary-types-in-asp-net-mvc
Workaround:
POST json dictionary
We used the stated workaround which has been fine. I'm not too clear as to when the fix will be shipped and where exactly the bug lay. (Is it .NET dependant / MVC dependant etc) If anyone else knows I'd love to find out :-)
Update
I haven't heard still if this is shipped (I assume it goes out with MVC 4?) but in the interim this may be an alternative solution:
http://www.dalsoft.co.uk/blog/index.php/2012/01/10/asp-net-mvc-3-improved-jsonvalueproviderfactory-using-json-net/
Update 2
This has now been shipped as a fix with MVC 4. The issue remains unresolved in MVC 3 and so I've now written it up as a blog post here:
http://icanmakethiswork.blogspot.com/2012/10/mvc-3-meet-dictionary.html
I ran into this issue too. After finding this SO post, I thought about upgrading to MVC4, but it's too risky to do all at once in my environment so scratch that.
This link posted in Johnny Reilly's answer looked promising, but it required flattening my dictionary to a string. Because my MVC model is bidirectional (it's used for reads and writes), and I really wanted that dictionary structure I decided to pass on that too. It would have been a real pain to keep two properties for one value. I would have needed to add more tests, watch out for edge cases, etc.
Johnny's JsonValueProviderFactory link seemed promising too, but a bit arcane. I'm also not entirely comfortable monkeying around with a part of MVC like that. I had only a few hours to figure this problem out so I passed on this too.
Then I found this link somewhere, and thought "Yes! this is more like what I want!". In other words attack the model binding problem by using a custom binder. Replace the buggy one with something else, and use MVC's built-in capability to do so. Unfortunately, this did not work as my use case was List of T, and T was my model. This totally did not work with the sample. So I hacked away at it and ultimately failed.
Then, I got a lightbulb moment - JSON.NET does not have this problem. I use it all the time for doing all sorts of things, from cloning objects, to logging, to REST service endpoints. Why not model binding? So I ultimately ended up with this and my problem was solved. I think it should work with just about anything - I trust JSON.NET =)
/// <summary>
/// Custom binder that maps JSON data in the request body to a model class using JSON.NET.
/// </summary>
/// <typeparam name="T">Model type being bound</typeparam>
/// <remarks>
/// This binder is very useful when your MVC3 model contains dictionaries, something that it can't map (this is a known bug, fixed with MVC 4)
/// </remarks>
public class CustomJsonModelBinder<T> : DefaultModelBinder
where T : class
{
/// <summary>
/// Binds the model by using the specified controller context and binding context.
/// </summary>
/// <returns>
/// The bound object.
/// </returns>
/// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><exception cref="T:System.ArgumentNullException">The <paramref name="bindingContext "/>parameter is null.</exception>
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
HttpRequestBase request = controllerContext.HttpContext.Request;
request.InputStream.Position = 0;
var input = new StreamReader(request.InputStream).ReadToEnd();
T modelObject = JsonConvert.DeserializeObject<T>(input);
return modelObject;
}
}
To apply the binder, I added an attribute to my model parameter. This causes MVC3 to use my binder instead of the default. Something like this:
public ActionResult SomeAction(
[ModelBinder(typeof(CustomJsonModelBinder<List<MyModel>>))] // This custom binder works around a known dictionary binding bug in MVC3
List<MyModel> myModelList, int someId)
{
One caveat - I was using POST with content type "application/json". If you're doing something like form or multipart data instead it will probably crash horribly.

In Composite WPF (Prism), what is the difference between IRegion.Add and IRegionManager.RegisterViewWithRegion?

In Composite WPF (Prism), when adding modules to the IRegionManger collection, what is the difference between using IRegion.Add and IRegionManager.RegisterViewWithRegion?
IRegion.Add
public void Initialize()
{
_regionManager.Regions["MainRegion"].Add( new ModuleAView() );
}
IRegionManager.RegisterViewWithRegion
public void Initialize()
{
_regionManager.RegisterViewWithRegion( "MainRegion", typeof( ModuleAView ) );
}
The difference is who is responsible for creating the view. In the IRegion.Add scenario (also called View Injection) you are responsible for instantiating the view beforehand. In the other scenario with RegisterViewWithRegion (also called View Discovery), the region manager instantiates the view itself.
There are some technical reasons you would want to do one or the other. For example
you had a more complicated way of creating views (maybe you want to create the View and its ViewModel and marry them by setting the DataContext property yourself), you'd need to use View Injection
if you take advantage of Region Scopes, you will be forced to use View Injection.
The relevant documenation is:
For View Composition (including View Injection vs. View Discovery and discussions of View-First or View-Presenter-First approaches):
http://msdn.microsoft.com/en-us/library/dd458944.aspx
There's also a really handy "when to use each" section. Here's the excerpt from the docs:
Explicit or programmatic control over when a view is created and
displayed, or when you need to
remove a view from a region, for
example, as a result of application
logic.
To display multiple instances of the same views into a region, where
each view instance is bound to
different data.
To control which instance of a region a view is added (for
example, if you want to add
customer detail view to a specific
customer detail region). Note that
this scenario requires scoped
regions described later in this
topic.
Hope this helps.
RegisterViewWithRegion raises the OnContentRegistered event, but of course that could not be the case depending on your DI

Resources