简体   繁体   English

如何将Javascript字典传递给C#字典值是对象的控制器

[英]How to pass Javascript dictionary to controller where C# dictionary value is an object

Imagine this Javascript dictionary: 想象一下这个Javascript字典:

var things = {};
things['1'] = 10;
things['2'] = 11;

Here's a little bit of ajax code: 这是一些ajax代码:

$.ajax({
    url: '/Controller/Foo',
    type: 'POST',
    data: {
        things: things
    },

Here's something that works: 这是可行的:

[HttpPost]
public IActionResult Foo(Dictionary<string, int> things)

things will show that 1 maps to 10 and 2 maps to 11. 事情将显示1映射到10和2映射到11。

Here's something that DOES NOT work: 这是行不通的:

[HttpPost]
public IActionResult Foo(Dictionary<string, object> things)

things will show that 1 maps to null and 2 maps to null. 事物将显示1映射为null和2映射为null。

I can not change the Dictionary types. 我无法更改字典类型。 In reality, that Dictionary is part of a complex object that is used throughout the application (on the C# side of things). 实际上,该Dictionary是整个应用程序中使用的复杂对象的一部分(在C#方面)。 What you are looking at is a dumbed-down example. 您正在查看的是一个愚蠢的示例。

In addition, JSON.stringify does not help at all. 另外,JSON.stringify完全没有帮助。 In fact, if I stringify the dictionary I get a count of 0, with no values. 实际上,如果我对字典进行字符串化处理,则我得到的计数为0,没有值。

Using C# to express my point, I think the expectation is more this (than what is currently happening): 使用C#来表达我的观点,我认为期望比当前要高得多:

int x = 5;
object foo = (object)x;

The dictionary was defined like this because one could be doing: 字典的定义是这样的,因为可以这样做:

things[key] = 1;

or 要么

things[key] = "string";

that's why it was declared as an object. 这就是为什么它被声明为对象。

I am using ASP.NET Core if that matters (and jquery 3.4.1). 如果重要的话,我正在使用ASP.NET Core(和jquery 3.4.1)。

Thank you. 谢谢。

You could custom a DictionaryModelBinder like below : 您可以自定义一个DictionaryModelBinder如下所示:

 public class DictionaryModelBinder:IModelBinder
{
    public  Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        var result = new Dictionary<string, object> {};
        var form = bindingContext.HttpContext.Request.Form;
        if (form==null)
        {
            bindingContext.ModelState.AddModelError("FormData", "The data is null");
            return Task.CompletedTask;
        }
        foreach ( var k in form.Keys){
            StringValues v = string.Empty;
            var flag = form.TryGetValue(k, out v);
            if (flag)
            { 
                result.Add(k, v );
            }
        }

        bindingContext.Result = ModelBindingResult.Success(result);
        return Task.CompletedTask;
    }
}

Controller : 控制器:

[HttpPost]
    public IActionResult Foo([ModelBinder(BinderType = typeof(DictionaryModelBinder))]Dictionary<string, object> things)
    {
        // the stuff you want
    }

I don't think you can bind to object as a parameter (or Dictionary value type) because: 我不认为您可以将object绑定为参数(或Dictionary值类型),因为:

A complex type must have a public default constructor and public writable properties to bind. 复杂类型必须具有公共默认构造函数和公共可写属性才能绑定。 When model binding occurs, the class is instantiated using the public default constructor. 发生模型绑定时,将使用公共默认构造函数实例化该类。

I think you could either strongly type your object (which sounds like it's not an option for you) or change your endpoint to take all its relevant properties distinctly as simple types ( string , bool , int , etc.). 我认为您可以强烈地键入object (这似乎不是您的选择),也可以更改端点以将其所有相关属性作为简单类型( stringboolint等)来区别对待。

Reference: Model Binding in ASP.NET Core 参考: ASP.NET Core中的模型绑定

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM