I'm working on a small library for for ASP.NET MVC 3 that should offer better reusability of model metadata and easy mapping from data entities from / to custom viewmodels. For this I need to be able to provide my own implementation of ICustomTypeDescriptor for three different areas of interest in ASP.NET MVC:
- Scaffolding
- Validation
- Modelbinding
It seems like this could be done by setting System.Web.Mvc.ModelMetadataProviders.Current
to my own CustomMetaDataProvider, but this is not nearly enough to cover all three points above.
The problem is that there are several classes in System.Web.M开发者_运维问答vc which call directly into this System.Web.TypeDescriptorHelper
which is not extensible because it looks like this:
internal static class TypeDescriptorHelper {
public static ICustomTypeDescriptor Get(Type type) {
return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
}
}
The only solution I found is very awkward and required subclassing lots of types from System.Web.Mvc to make it work. I even had to re-implement CustomModelBinderDictionary
completely only to overwrite one or two lines of code. So it works, but it is a very messy hack and likely to break the next time I update to a new ASP.NET MVC version.
So here's what I like to know : Did I miss any simple way to do this?
Bonus question: If not and you are from the MVC team, could you consider creating an appropriate extensibility point in MVC 4 ;-)?
Edit: In reply to the question why I need to code my own TypeDescriptor: There are several reasons for this: 1. Most important: I need a workaround for the problem described at https://forums.asp.net/t/1614439.aspx/1 2. Also, I need to insert metadata dynamically for various reasons. For example I want to code my own Bind attribute, but BindAttribute is sealed. So instead of deriving from it, I am emitting a matching BindAttribute dynamically from the TypeDescriptor when detecting my own bind attribute implementation.
According to Brad Wilson (an ASP.NET MVC team member) this issue has been put on the bug list for MVC 4. So it seems there is no good solution for the moment, but hopefully this will be solved when MVC 4 comes out.
For anyone interested in my library for reusable validation and scaffolding metadata and model / viewmodel mapping, feel free to subscribe my blog at https://devermind.wordpress.com/. I'm going to release the library there.
I'm not sure what it is that you're trying to do with custom implementations of Validation, ModelBinding and potentially ModelMetadata, that can't be done with the DependencyResolver functionality in MVC?
The new scaffolding support in the recent Tooling Update for MVC 3 may meet your needs for scaffolding; however I would take a look at possibly hooking into the DependencyResolver functionality for the ModelBinding, ModelMetadata and Validation and see if they can achieve what you are looking for. I had a similar situation recently where I needed to implement a lot of these behaviors from scratch to provide a flexible framework, and I was able to do so with just ModelMetadata and Validation providers using IoC. I also ended up inheriting DynamicObject (or ExpandoObject) in a few cases to give even more flexibility. I know this isn't exactly a direct answer but I'm not sure why you would need access to anything lower than these extensability points?
EDIT: If you're looking to reuse ModelMetadata on similar ViewModels to avoid having to redefine the same ModelMetadata over in multiple places, you might want to consider the implications of this. There are many times when you want certain data restrictions on your entities but these restrictions should be on the DataModel and not the ViewModel. The user may have a slightly more restrictive rules. For example, you may stipulate that certain fields are readonly for the user in the ViewModel, but that the entity used as a DataModel does allow you to modify the value (typically from within your code). Similarly you may run into situations where the ModelMetadata used to generate the Create view for the VideModel might be slightly different than the ViewModel used for the Edit view. Reusing them may seem like a great way to stay consistent and reduce code duplication but it may be something you regret later on. I recently ran into the same issue where I wanted to avoid writing a new ViewModel for each view that may cause a postback, I haven't found a perfect solution I like but I think reusing the ModelMetadata will cause more problems that it might solve in my opinion. Writing ViewModels for views that need them will also probably eliminate your need to implement a custom BindAttribute implementation and the Scaffolding issue. If I'm right in assuming not wanting to create so many ViewModels with their own Metadata is what's causing you to try and find implementations of a custom BindAttribute, custom Scaffolding, custom ModelMetadata, custom Validation and custom ModelBinding... it may be worth looking at how much time it would actually take to just create the ViewModels.
If you find a better approach, feel free to let me know :-)
精彩评论