C# ASP.NET是否将具有异常键名的表单POST反序列化为适当的DataContract模型?

C# ASP.NET是否将具有异常键名的表单POST反序列化为适当的DataContract模型?,c#,asp.net,.net,.net-core,C#,Asp.net,.net,.net Core,我对C#和ASP.NET有些陌生,我的任务是用新的ASP.NET核心MVC API服务替换应用程序。我还有一个遗留应用程序,需要向其中发布一些数据,但我无法控制它的代码,也无法更改它的行为。它希望以应用程序/x-www-form-urlencoded的形式发送数据,并且当映射回POCO数据协定对象时,大写参数名称包含“无效”字符,例如,或者名称以数字开头 来自旧应用程序的示例请求可能如下所示: POST /something HTTP/1.0 Accept: text/html,applicat

我对C#和ASP.NET有些陌生,我的任务是用新的ASP.NET核心MVC API服务替换应用程序。我还有一个遗留应用程序,需要向其中发布一些数据,但我无法控制它的代码,也无法更改它的行为。它希望以
应用程序/x-www-form-urlencoded
的形式发送数据,并且当映射回POCO数据协定对象时,大写参数名称包含“无效”字符,例如
,或者名称以数字开头

来自旧应用程序的示例请求可能如下所示:

POST /something HTTP/1.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 42

USERNAME=somebody&ACCOUNT=123&APP.SESSID=acbd18db4cc2f85cedef654fccc4a4d8&1STCOLOR=BLUE
因为我不能,也有点不想,创建一个像这样无效代码的DataContract模型,所以我不确定如何继续

class InputModel
{
    public string USERNAME { get; set; }
    public int ACCOUNT { get; set; }
    public string APP.SESSID { get; set; }
    public string 1STCOLOR { get; set; }
}
最好是,我希望尽可能使数据模型成员名人性化(例如,
APP.sessiond
ApplicationSessionID
),并且能够在表单数据反序列化时或在模型绑定期间,或诸如此类的情况下,将遗留参数名绑定到人性化成员名


我只是不知道在ASP.NET核心代码中查找什么或搜索什么来帮助我确定应该做什么来覆盖默认的表单反序列化行为。这里有经验的人能帮忙吗?谢谢你的时间

我想我知道了。我首先必须创建一个
ValueProvider
对象。这就是我想到的

public class MyValueProvider : BindingSourceValueProvider, IValueProvider
{
    private IEnumerable<KeyValuePair<string, string>> _keyMap;
    private readonly CultureInfo _culture;
    private PrefixContainer _prefixContainer;
    private IFormCollection _values;

    public MyValueProvider(BindingSource form, IFormCollection values, CultureInfo culture) : this(form, values, null, culture) { }

    public MyValueProvider(BindingSource form, IFormCollection values, IEnumerable<KeyValuePair<string, string>> keyMap, CultureInfo culture) : base(form)
    {
        if (form == null)
        {
            throw new ArgumentNullException(nameof(form));
        }

        if (values == null)
        {
            throw new ArgumentNullException(nameof(values));
        }


        _values = values;
        _culture = culture;
        _keyMap = keyMap;
    }

    public CultureInfo Culture
    {
        get { return _culture; }
    }

    protected PrefixContainer PrefixContainer
    {
        get
        {
            if (_prefixContainer == null)
            {
                _prefixContainer = new PrefixContainer(_values.Keys);
            }
            return _prefixContainer;
        }
    }

    public override bool ContainsPrefix(string prefix)
    {
        return PrefixContainer.ContainsPrefix(prefix);
    }

    public virtual IDictionary<string, string> GetKeysFromPrefix(string prefix)
    {
        if (prefix == null)
        {
            throw new ArgumentNullException(nameof(prefix));
        }

        return PrefixContainer.GetKeysFromPrefix(prefix);
    }

    public override ValueProviderResult GetValue(string key)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }

        var pair = _keyMap.FirstOrDefault(map => map.Key.EndsWith(key));
        if (pair.Value == null)
        {
            return ValueProviderResult.None;
        }
        var values = _values[pair.Value];
        if (values.Count == 0)
        {
            return ValueProviderResult.None;
        }

        return new ValueProviderResult(values, Culture);
    }
}

最后,这很简单。我花了一点时间才弄明白这个过程。

我想我已经弄明白了。我首先必须创建一个
ValueProvider
对象。这就是我想到的

public class MyValueProvider : BindingSourceValueProvider, IValueProvider
{
    private IEnumerable<KeyValuePair<string, string>> _keyMap;
    private readonly CultureInfo _culture;
    private PrefixContainer _prefixContainer;
    private IFormCollection _values;

    public MyValueProvider(BindingSource form, IFormCollection values, CultureInfo culture) : this(form, values, null, culture) { }

    public MyValueProvider(BindingSource form, IFormCollection values, IEnumerable<KeyValuePair<string, string>> keyMap, CultureInfo culture) : base(form)
    {
        if (form == null)
        {
            throw new ArgumentNullException(nameof(form));
        }

        if (values == null)
        {
            throw new ArgumentNullException(nameof(values));
        }


        _values = values;
        _culture = culture;
        _keyMap = keyMap;
    }

    public CultureInfo Culture
    {
        get { return _culture; }
    }

    protected PrefixContainer PrefixContainer
    {
        get
        {
            if (_prefixContainer == null)
            {
                _prefixContainer = new PrefixContainer(_values.Keys);
            }
            return _prefixContainer;
        }
    }

    public override bool ContainsPrefix(string prefix)
    {
        return PrefixContainer.ContainsPrefix(prefix);
    }

    public virtual IDictionary<string, string> GetKeysFromPrefix(string prefix)
    {
        if (prefix == null)
        {
            throw new ArgumentNullException(nameof(prefix));
        }

        return PrefixContainer.GetKeysFromPrefix(prefix);
    }

    public override ValueProviderResult GetValue(string key)
    {
        if (key == null)
        {
            throw new ArgumentNullException(nameof(key));
        }

        var pair = _keyMap.FirstOrDefault(map => map.Key.EndsWith(key));
        if (pair.Value == null)
        {
            return ValueProviderResult.None;
        }
        var values = _values[pair.Value];
        if (values.Count == 0)
        {
            return ValueProviderResult.None;
        }

        return new ValueProviderResult(values, Culture);
    }
}
最后,这很简单。我花了一点时间才弄明白这个过程

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(options =>
        {
            options.ValueProviderFactories.Insert(0, new MyValueProviderFactory(Configuration.GetSection("MyValueProviderKeyMap")));
        });
    }
}