如何在ASP.NET MVC中提供自己的ICustomTypeDescriptor?

时间:2022-12-02 10:09:01

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:

我正在为ASP.NET MVC 3开发一个小型库,它应该提供更好的模型元数据可重用性,以及从/向自定义视图模型轻松映射数据实体。为此,我需要能够为ASP.NET MVC中三个不同的感兴趣区域提供我自己的ICustomTypeDescriptor实现:

  1. Scaffolding
  2. 脚手架
  3. Validation
  4. 验证
  5. Modelbinding
  6. 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.

看起来这可以通过将System.Web.Mvc.ModelMetadataProviders.Current设置为我自己的CustomMetaDataProvider来完成,但这还不足以覆盖上面的所有三点。

The problem is that there are several classes in System.Web.Mvc which call directly into this System.Web.TypeDescriptorHelper which is not extensible because it looks like this:

问题是System.Web.Mvc中有几个类直接调用这个不可扩展的System.Web.TypeDescriptorHelper,因为它看起来像这样:

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.

我发现的唯一解决方案非常笨拙,需要从System.Web.Mvc中继承许多类型以使其工作。我甚至不得不完全重新实现CustomModelBinderDictionary,只是为了覆盖一行或两行代码。所以它可行,但它是一个非常混乱的黑客,并可能在下次更新到新的ASP.NET MVC版本时中断。

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 ;-)?

奖金问题:如果没有,你来自MVC团队,你能考虑在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.

编辑:回答问题为什么我需要编写自己的TypeDescriptor代码:有几个原因:1。最重要的是:我需要针对https://forums.asp.net/t/1614439中描述的问题的解决方法.aspx / 1 2.此外,由于各种原因,我需要动态插入元数据。例如,我想编写自己的Bind属性,但BindAttribute是密封的。因此,在检测我自己的绑定属性实现时,我会从TypeDescriptor动态发出匹配的BindAttribute,而不是从中派生。

2 个解决方案

#1


1  

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.

根据Brad MV(ASP.NET MVC团队成员)的说法,这个问题已被列入MVC 4的错误列表。所以目前似乎没有好的解决方案,但希望这将在MVC 4发布时解决。

For anyone interested in my library for reusable validation and scaffolding metadata and model / viewmodel mapping, feel free to subscribe my blog at http://devermind.com. I'm going to release the library there in a couple of weeks.

对于任何对我的库感兴趣的可重用验证和脚手架元数据以及模型/视图模型映射的人,请随时在http://devermind.com上订阅我的博客。我将在几周内发布那里的图书馆。

#2


0  

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?

我不确定您尝试使用Validation,ModelBinding和可能的ModelMetadata的自定义实现是什么,而这些实现无法通过MVC中的DependencyResolver功能完成?

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?

最近的MVC 3工具更新中的新脚手架支持可满足您对脚手架的需求;但是我会看一下可能挂钩到ModelBinding,ModelMetadata和Validation的DependencyResolver功能,看看它们是否能达到你想要的效果。最近我遇到了类似的情况,我需要从头开始实现很多这些行为,以提供灵活的框架,而我只能使用IoC使用ModelMetadata和Validation提供程序。我还最终在少数情况下继承了DynamicObject(或ExpandoObject),以提供更大的灵活性。我知道这不是一个直接的答案,但我不确定为什么你需要访问低于这些可扩展点的任何东西?

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.

编辑:如果您希望在类似的ViewModel上重用ModelMetadata以避免在多个位置重新定义相同的ModelMetadata,您可能需要考虑这一点的含义。很多时候您希望对实体进行某些数据限制,但这些限制应该在DataModel而不是ViewModel上。用户可能具有稍微更严格的规则。例如,您可以规定ViewModel中的某些字段对于用户是只读的,但是用作DataModel的实体允许您修改该值(通常在您的代码中)。类似地,您可能会遇到用于生成VideModel的Create视图的ModelMetadata可能与用于Edit视图的ViewModel略有不同的情况。重用它们似乎是保持一致性和减少代码重复的好方法,但它可能是您后来后悔的事情。我最近遇到了同样的问题,我想避免为可能导致回发的每个视图编写一个新的ViewModel,我还没有找到一个我喜欢的完美解决方案,但我认为重用ModelMetadata会导致更多可能解决的问题我的想法。为需要它们的视图编写ViewModel也可能无需实现自定义BindAttribute实现和Scaffolding问题。如果我正确地假设不想创建如此多的具有自己元数据的ViewModel,那么是什么导致您尝试查找自定义BindAttribute,自定义Scaffolding,自定义ModelMetadata,自定义验证和自定义ModelBinding的实现...它可能是值得的看看创建ViewModel实际需要多长时间。

If you find a better approach, feel free to let me know :-)

如果您找到更好的方法,请随时告诉我:-)

#1


1  

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.

根据Brad MV(ASP.NET MVC团队成员)的说法,这个问题已被列入MVC 4的错误列表。所以目前似乎没有好的解决方案,但希望这将在MVC 4发布时解决。

For anyone interested in my library for reusable validation and scaffolding metadata and model / viewmodel mapping, feel free to subscribe my blog at http://devermind.com. I'm going to release the library there in a couple of weeks.

对于任何对我的库感兴趣的可重用验证和脚手架元数据以及模型/视图模型映射的人,请随时在http://devermind.com上订阅我的博客。我将在几周内发布那里的图书馆。

#2


0  

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?

我不确定您尝试使用Validation,ModelBinding和可能的ModelMetadata的自定义实现是什么,而这些实现无法通过MVC中的DependencyResolver功能完成?

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?

最近的MVC 3工具更新中的新脚手架支持可满足您对脚手架的需求;但是我会看一下可能挂钩到ModelBinding,ModelMetadata和Validation的DependencyResolver功能,看看它们是否能达到你想要的效果。最近我遇到了类似的情况,我需要从头开始实现很多这些行为,以提供灵活的框架,而我只能使用IoC使用ModelMetadata和Validation提供程序。我还最终在少数情况下继承了DynamicObject(或ExpandoObject),以提供更大的灵活性。我知道这不是一个直接的答案,但我不确定为什么你需要访问低于这些可扩展点的任何东西?

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.

编辑:如果您希望在类似的ViewModel上重用ModelMetadata以避免在多个位置重新定义相同的ModelMetadata,您可能需要考虑这一点的含义。很多时候您希望对实体进行某些数据限制,但这些限制应该在DataModel而不是ViewModel上。用户可能具有稍微更严格的规则。例如,您可以规定ViewModel中的某些字段对于用户是只读的,但是用作DataModel的实体允许您修改该值(通常在您的代码中)。类似地,您可能会遇到用于生成VideModel的Create视图的ModelMetadata可能与用于Edit视图的ViewModel略有不同的情况。重用它们似乎是保持一致性和减少代码重复的好方法,但它可能是您后来后悔的事情。我最近遇到了同样的问题,我想避免为可能导致回发的每个视图编写一个新的ViewModel,我还没有找到一个我喜欢的完美解决方案,但我认为重用ModelMetadata会导致更多可能解决的问题我的想法。为需要它们的视图编写ViewModel也可能无需实现自定义BindAttribute实现和Scaffolding问题。如果我正确地假设不想创建如此多的具有自己元数据的ViewModel,那么是什么导致您尝试查找自定义BindAttribute,自定义Scaffolding,自定义ModelMetadata,自定义验证和自定义ModelBinding的实现...它可能是值得的看看创建ViewModel实际需要多长时间。

If you find a better approach, feel free to let me know :-)

如果您找到更好的方法,请随时告诉我:-)