ASP.NET MVC XML绑定Action参数列表

昨天查看了 ASP.NET MVC 的生命周期,并没有找到类似的解决方案。

不过今天在 stackoverflow上找到了解决方案,没耐心的同学可以直接戳原文拷贝代码,原文地址:How to pass XML as POST to an ActionResult in ASP MVC .NET

看了外国同学的说明,才发现 MVC居然可以根据不同的请求 Content Type来选择 ValueProvider,这样提供了很好的扩展。

MVC本身提供了 JsonValueProviderFactory,顾名思义就是为 Json服务的。那么在这里我们需要提供为 XML服务的ValueProviderFactory。

第一步:创建 XMLValueProviderFactory

public class XmlValueProviderFactory : ValueProviderFactory
    {
        private static void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, XElement xmlDoc)
        {
            // Check the keys to see if this is an array or an object
            var uniqueKeys = new List<string>();
            int totalCount = 0;
            foreach (XElement element in xmlDoc.Elements())
            {
                if (!uniqueKeys.Contains(element.Name.LocalName))
                    uniqueKeys.Add(element.Name.LocalName);

                totalCount++;
            }

            bool isArray;
            if (uniqueKeys.Count == 1)
            {
                isArray = true;
            }
            else if (uniqueKeys.Count == totalCount)
            {
                isArray = false;
            }
            else
            {
                // Not sure how to deal with a XML doc that has some keys the same, but not all
                // For now don‘t process this node
                return;
            }

            // Add the elements to the backing store
            int elementCount = 0;
            foreach (XElement element in xmlDoc.Elements())
            {
                if (element.HasElements)
                {
                    if (isArray)
                    {
                        // Omit local name for arrays and add index instead
                        AddToBackingStore(backingStore, $"{prefix}[{elementCount}]", element);
                    }
                    else
                    {
                        AddToBackingStore(backingStore, MakePropertyKey(prefix, element.Name.LocalName), element);
                    }
                }
                else
                {
                    backingStore.Add(MakePropertyKey(prefix, element.Name.LocalName), element.Value);
                }

                elementCount++;
            }
        }

        private static XDocument GetDeserializedXml(ControllerContext controllerContext)
        {
            var contentType = controllerContext.HttpContext.Request.ContentType;
            if (!contentType.StartsWith("text/xml", StringComparison.OrdinalIgnoreCase)
                && !contentType.StartsWith("application/xml", StringComparison.OrdinalIgnoreCase))
            {
                // Are there any other XML mime types that are used? (Add them here)

                // not XML request
                return null;
            }

            XDocument xml;
            try
            {
                // DTD processing disabled to stop XML bomb attack - if you require DTD processing, read this first: http://msdn.microsoft.com/en-us/magazine/ee335713.aspx
                var xmlReaderSettings = new XmlReaderSettings {DtdProcessing = DtdProcessing.Prohibit};
                var xmlReader = XmlReader.Create(controllerContext.HttpContext.Request.InputStream, xmlReaderSettings);
                xml = XDocument.Load(xmlReader);
            }
            catch (Exception)
            {
                return null;
            }

            if (xml.FirstNode == null)
            {
                // No XML data
                return null;
            }

            return xml;
        }

        private static string MakeArrayKey(string prefix, int index)
        {
            return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
        }

        private static string MakePropertyKey(string prefix, string propertyName)
        {
            return (prefix.IsNullOrEmpty()) ? propertyName : prefix + "." + propertyName;
        }

        #region ValueProviderFactory Members

        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            var xmlData = GetDeserializedXml(controllerContext);
            if (xmlData == null)
                return null;

            var backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            AddToBackingStore(backingStore, String.Empty, xmlData.Root);
            return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
        }

        #endregion
    }

该段代码属于网上抄袭,基本没有改,在下觉得这样已经满足需求了,原文地址:Sending XML to an ASP.NET MVC Action Method Argument

PS:如果涉及版权问题,请告知在下。

第二步:在 Global.asmx.cs 的 Application_Start 方法中注册 ValueProviderFactory

 
ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
ValueProviderFactories.Factories.Add(new XmlValueProviderFactory());
 

亲测可用,如有问题,请留言。

时间: 2024-10-18 20:01:21

ASP.NET MVC XML绑定Action参数列表的相关文章

[转] ASP.NET MVC 模型绑定的功能和问题

摘要:本文将与你深入探究 ASP.NET MVC 模型绑定子系统的核心部分,展示模型绑定框架的每一层并提供扩展模型绑定逻辑以满足应用程序需求的各种方法. 同时,你还会看到一些经常被忽视的模型绑定技术,并了解如何避免一些最常见的模型绑定错误. ASP.NET MVC 模型绑定通过引入自动填充控制器操作参数的抽象层.处理通常与使用 ASP.NET 请求数据有关的普通属性映射和类型转换代码来简化控制器操作. 虽然模型绑定看起来很简单,但实际上是一个相对较复杂的框架,由许多共同创建和填充控制器操作所需对

ASP.NET MVC Model绑定(二)

ASP.NET MVC Model绑定(二) 前言 上篇对于Model绑定的简单演示想必大家对Model绑定的使用方式有一点的了解,那大家有没有想过Model绑定器是在什么时候执行的?又或是执行的过程是什么样的?将在本篇为大家解除这些疑惑,在其中涉及到的一些描述类型和上下文参数会在后续的篇幅中讲到. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC框架中的位置 MVC中的默认Model绑定器生成过程 IModelBinderProvider的简单

ASP.NET MVC Model绑定(六)

ASP.NET MVC Model绑定(六) 前言 前面的篇幅对于IValueProvider的使用做个基础的示例讲解,但是没并没有对 IValueProvider类型的实现做详细的介绍,然而MVC框架中给我们提供了几种默认的实现类型,在本篇中将会对NameValueCollectionValueProvider类型做一个示例讲解,了解一下MVC框架给我们提供的值提供程序是怎么处理Model值的. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC

ASP.NET MVC Model绑定(五)

ASP.NET MVC Model绑定(五) 前言 前面的篇幅对于IValueProvider的获取位置和所处的生成过程做了讲解,本篇将会对IValueProvider的使用做个基础的示例讲解,读完本篇你将会对IValueProvider有个更清晰的印象. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC框架中的位置 MVC中的默认Model绑定器生成过程 IModelBinderProvider的简单应用 IValueProvider在MVC框

ASP.NET MVC Model绑定(一)

ASP.NET MVC Model绑定(一) 前言 ModelMetadata系列的结束了,从本篇开始就进入Model绑定部分了,这个系列阅读过后你会对Model绑定有个比较清楚的了解, 本篇对于Model绑定器的最基础的应用作个简单的示例展示,目的在于让大家事先了解一下Model绑定器是什么样的便于后续篇幅的理解. Model绑定 IModelBinder.自定义Model绑定器简单实现 Model绑定器在MVC框架中的位置 MVC中的默认Model绑定器生成过程 IModelBinderPr

ASP.NET MVC Model绑定(四)

ASP.NET MVC Model绑定(四) 前言 前面的篇幅对于Model绑定器IModelBinder以及实现类型.Model绑定器提供程序都作了粗略的讲解,可以把Model绑定器想象成一个大的容器,为什么这么说呢?留个疑问在这里. 首先控制器的方法参数可能是很多种类型的.可能是多个同一种类型的,应对这种情况MVC框架使用的绑定实现都是IValueProvider来做的,而针对参数类型的不同等等一些情况,IValueProvider的实现类型也是有很大的差异的,这些具体实现的讲解会在后续的篇

ASP.NET MVC Model绑定(三)

ASP.NET MVC Model绑定(三) 前言 看过前两篇的朋友想必对Model绑定有个大概的了解,然而MVC框架给我们提供了更高的可扩展性的提供程序编程模式,也就是本篇的主题了,会讲解一下Model绑定器提供程序的实现以及解决一下上篇遗留的问题. 第一个问题是ModelBinderProviderCollection类型的执行过程? 还有个本篇的问题就是同样的向系统上下文中注册Model绑定器和Model绑定器提供程序,哪一个优先级更高? Model绑定 IModelBinder.自定义M

(五)ASP.NET MVC 中关于 Action 的参数

在ASP.NET MVC 的 Controller 类下有多个 Method,如果这些 Method 都是 public 修饰的和返回值类型是 ActionResult 类型的,这些方法就时 Action.通过 "Controller 名字/方法名" 访问的时候就会执行对应的方法. Action 有三种类型的参数:普通参数,Model 类, FormCollection. 普通参数:构架会自动把用户请求的值根据参数名字映射到对应的值. Model 类:这种类叫 ViewModel Fo

ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)

前面文章介绍了ASP.NET MVC中的模型绑定和验证功能,本着ASP.NET MVC没有魔法的精神,本章内容将从代码的角度对ASP.NET MVC如何完成模型的绑定和验证进行分析,已了解其原理. 本文的主要内容有: ● ModelBinder ● ValuePrivoder ● ModelMetadata ● 简单模型与复杂模型 ● 小结 ModelBinder ModelBinder是ASP. NET MVC用于模型绑定的核心组件,所有的ModelBinder都实现了IModelBinder