ASP.NET Web API 控制器无法处理动态对象?

发布于 2025-01-08 14:29:50 字数 730 浏览 1 评论 0原文

在我的代码中,我有一个基类 Foo,我的所有对象都继承自 Foo 对象。 假设我有一个这样的类,

public class Bar : Foo {
    public string Heading { get;set; }
}

我尝试将 ApiControllers put 方法与动态一起使用,但出现此错误 http: //paste2.org/p/1914054

这是我在 ApiController 中使用的代码

public void Put(string id, dynamic model) {
    //do stuff
}

如果我使用普通控制器,我可以使用动态来发布数据。是否可以添加使 api 控制器动态工作,或者我是否需要构建自己的模型绑定器?

看起来有些人认为即使在 MVC 3 中输入参数也不能是动态的,但事实并非如此,这就是我问这个问题的原因。 这个MVC 3 中的控制器使用动态作为输入参数效果非常好。

In my code I have a base class Foo and all my objects inherits from the Foo object.
So let's say I have a class like this

public class Bar : Foo {
    public string Heading { get;set; }
}

I have tried to use the ApiControllers put method with dynamic but I get this error http://paste2.org/p/1914054

This is the code I'm using in the ApiController

public void Put(string id, dynamic model) {
    //do stuff
}

If I use a normal controller I can use dynamic to post data. Is it possible to add make the api controller work with dynamic or do I need to build my own model binder?

It sees like some thinks that even in MVC 3 the input parameters can't be a dynamic but that is not true and that's why I ask this question. This controller in MVC 3 works just great with dynamic as input parameter.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不爱素颜 2025-01-15 14:29:50

嗯,我可以使用 ASP.NET Web API 方法来完成此操作:

    public string Post(dynamic value)
    {
        string s = "";
        foreach (dynamic item in value)
        {
            s = s + item.content + " ";
        }
        return s;
    }

使用 JSON 数组:

POST http://localhost:6946/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:6946
Content-Length: 327
Content-Type: application/json
[{"content":"Hello","editing":false},{"content":"sfsdf","editing":false},{"content":"sadsdfdsf","editing":false},{"content":"dfsdf","editing":false},{"content":"dsfsd","editing":false},{"content":"sdfsdf","editing":false},{"content":"dsf","editing":false},{"content":"dfg","editing":false},{"content":"fsdfsd","editing":false}]

并且它有效......

Hm, I was able to just do this with an ASP.NET Web API method:

    public string Post(dynamic value)
    {
        string s = "";
        foreach (dynamic item in value)
        {
            s = s + item.content + " ";
        }
        return s;
    }

using a JSON array:

POST http://localhost:6946/api/values HTTP/1.1
User-Agent: Fiddler
Host: localhost:6946
Content-Length: 327
Content-Type: application/json
[{"content":"Hello","editing":false},{"content":"sfsdf","editing":false},{"content":"sadsdfdsf","editing":false},{"content":"dfsdf","editing":false},{"content":"dsfsd","editing":false},{"content":"sdfsdf","editing":false},{"content":"dsf","editing":false},{"content":"dfg","editing":false},{"content":"fsdfsd","editing":false}]

And it worked....

独夜无伴 2025-01-15 14:29:50

看起来有些人认为即使在 MVC 3 中输入参数也不能
充满活力

我想是的。让我们看一下提供的示例:

[HttpPost]
[ValidateInput(false)]
public virtual ActionResult Update(dynamic editorModel) {

    if (!TryUpdateModel(_model, "CurrentModel")) {
        var parentId = _model.Parent != null ? (string)_model.Parent.Id : null;
        var viewModel = new EditViewModel
        {
            RootModel = _session.Query<IPageModel>()
                .Where(model => model.Parent == null)
                .SingleOrDefault(),
            CurrentModel = _model,
            ParentModel = parentId != null ? _session.Load<IPageModel>(parentId) : null,
        };
        return View("edit", viewModel);
    }

    UpdateModel(_model);

    _model.Metadata.Changed = DateTime.Now;
    _model.Metadata.Published = _model.Metadata.IsPublished ? DateTime.Now : default(DateTime?);
    _model.Metadata.ChangedBy = HttpContext.User.Identity.Name;

    _repository.SaveChanges();
    _repository.Refresh(_model);

    var page = _model as IPageModel;

    if (page.Parent != null) {
        _model = _repository.SingleOrDefault<IPageModel>(m => m.Id == page.Parent.Id);
    }

    return RedirectToAction("index", new { model = _model });
}

您能告诉我这个 editorModel 动态变量在这个控制器操作中如何使用/在哪里使用吗?

为了进一步简化这个控制器操作,它是有效的,因为它从不使用作为参数传递的动态变量。我对其进行了简化,以更好地说明此操作在模型绑定方面的大致作用(当然,丢弃我们在这里不感兴趣的所有基础设施噪音来说明问题):

[HttpPost]
public ActionResult Update(dynamic blablabla)
{
    dynamic model = new MyViewModel();
    UpdateModel(model);
    // at this stage the model will be correctly bound

    return View(model);
}

在此操作中,TryUpdateModel UpdateModel 方法在 _model 实例变量上调用,该变量在构造函数中传递,类型为 IPageModel。 ASP.NET MVC 不可能知道(当然没有自定义模型绑定器)动态操作参数的类型。只需运行此代码,在 Update 操作中放置一个断点,并观察 editorModel 变量的类型。它只是System.Object。没有奇迹。

所以对我来说,这在 ASP.NET Web API 中的工作原理是完全正常的。

It sees like some thinks that even in MVC 3 the input parameters can't
be a dynamic

I think so. Let's take a look at the provided example:

[HttpPost]
[ValidateInput(false)]
public virtual ActionResult Update(dynamic editorModel) {

    if (!TryUpdateModel(_model, "CurrentModel")) {
        var parentId = _model.Parent != null ? (string)_model.Parent.Id : null;
        var viewModel = new EditViewModel
        {
            RootModel = _session.Query<IPageModel>()
                .Where(model => model.Parent == null)
                .SingleOrDefault(),
            CurrentModel = _model,
            ParentModel = parentId != null ? _session.Load<IPageModel>(parentId) : null,
        };
        return View("edit", viewModel);
    }

    UpdateModel(_model);

    _model.Metadata.Changed = DateTime.Now;
    _model.Metadata.Published = _model.Metadata.IsPublished ? DateTime.Now : default(DateTime?);
    _model.Metadata.ChangedBy = HttpContext.User.Identity.Name;

    _repository.SaveChanges();
    _repository.Refresh(_model);

    var page = _model as IPageModel;

    if (page.Parent != null) {
        _model = _repository.SingleOrDefault<IPageModel>(m => m.Id == page.Parent.Id);
    }

    return RedirectToAction("index", new { model = _model });
}

Can you point me how/where exactly is this editorModel dynamic variable used inside this controller action?

And to even further simplify this controller action, it works, because it never never uses the dynamic variable passed as argument. I have simplified it to better illustrate what this action is roughly doing concerning model binding (throwing away of course all the infrastructure noise that we are not interested in here to illustrate the problem):

[HttpPost]
public ActionResult Update(dynamic blablabla)
{
    dynamic model = new MyViewModel();
    UpdateModel(model);
    // at this stage the model will be correctly bound

    return View(model);
}

Inside this action the TryUpdateModel and UpdateModel methods are called on the _model instance variable which is passed in the constructor and is of type IPageModel. ASP.NET MVC cannot possibly know (without a custom model binder of course) the type of your dynamic action argument. Just run this code, put a breakpoint inside the Update action and observe the type of the editorModel variable. It will simply be System.Object. There are no miracles.

So it's for me it's perfectly normal that this works the same in ASP.NET Web API.

朦胧时间 2025-01-15 14:29:50

http://www.binaryintellect.net/articles/589f6915-f4c0-4bf9-9f94-4d00bd445c16.aspx

这个解决方案工作得很好。

我有一个 HTML 表单,其中所有输入控件都是动态的。很难将表单数据传输到 MVC 控制器,然后再传输到 Web Api 2 控制器。

您的服务器端 Web api 方法需要像

public string Post(FormDataCollection form){
... }

FormDataCollection 一样驻留在 System.Net.Http.Formatting 命名空间中。

如果您直接从网页(jquery)提供数据,那么上面的链接解决方案可以正常工作。

如果您将数据网页发布到 MVC 页面(c# 代码),然后进一步发布到 Web api 方法,则代码如下所示:

[HttpPost]
    public async Task<string> MasterDraw(FormCollection body)
    {
        HttpClient client = new HttpClient();
        KeyValuePair<string, string>[] list = null;
        string url = ConfigurationManager.AppSettings["BaseServiceUrl"] + "/api/MasterOperation/addrecord";

        if (body != null && body.HasKeys())
        {
            list = new KeyValuePair<string, string>[body.AllKeys.Count()];
            for (int ctr = 0; ctr < body.Keys.Count; ctr++ )
            {
                list[ctr] = new KeyValuePair<string, string>(body.Keys[ctr], body.GetValue(body.Keys[ctr]).AttemptedValue);
            }
        }

        var content = new FormUrlEncodedContent(list);

        HttpResponseMessage response = await client.PostAsync(url, content);

        // Check that response was successful or throw exception
        response.EnsureSuccessStatusCode();

        // Read response asynchronously as JToken and write out top facts for each country
        string contentRes = response.Content.ReadAsStringAsync().Result;

        return contentRes;
    }

浏览器端代码:

$('#btn-save').on('click', function (event) {
            var postUrl = "@Url.Action("masterdraw","masterrender")";

            var result = $.ajax({
                type: "POST",
                data: $('#form').serialize(),
                url: postUrl                    
            });

            // insert your jquery .done and .error methods

        });

http://www.binaryintellect.net/articles/589f6915-f4c0-4bf9-9f94-4d00bd445c16.aspx

This solution works perfectly fine.

I had an HTML form where all the input controls were dynamic. Had a hard time plumbing the form data to MVC controller and then again to Web Api 2 controller.

Your server side web api method needs to be like

public string Post(FormDataCollection form){
... }

FormDataCollection resides in System.Net.Http.Formatting namespace.

If you are posing data directly from a web page (jquery), then the above link solution is works fine.

If you posting data web page to an MVC page (c# code) which is then further posted to a web api method, then the code looks like this:

[HttpPost]
    public async Task<string> MasterDraw(FormCollection body)
    {
        HttpClient client = new HttpClient();
        KeyValuePair<string, string>[] list = null;
        string url = ConfigurationManager.AppSettings["BaseServiceUrl"] + "/api/MasterOperation/addrecord";

        if (body != null && body.HasKeys())
        {
            list = new KeyValuePair<string, string>[body.AllKeys.Count()];
            for (int ctr = 0; ctr < body.Keys.Count; ctr++ )
            {
                list[ctr] = new KeyValuePair<string, string>(body.Keys[ctr], body.GetValue(body.Keys[ctr]).AttemptedValue);
            }
        }

        var content = new FormUrlEncodedContent(list);

        HttpResponseMessage response = await client.PostAsync(url, content);

        // Check that response was successful or throw exception
        response.EnsureSuccessStatusCode();

        // Read response asynchronously as JToken and write out top facts for each country
        string contentRes = response.Content.ReadAsStringAsync().Result;

        return contentRes;
    }

The browser side code:

$('#btn-save').on('click', function (event) {
            var postUrl = "@Url.Action("masterdraw","masterrender")";

            var result = $.ajax({
                type: "POST",
                data: $('#form').serialize(),
                url: postUrl                    
            });

            // insert your jquery .done and .error methods

        });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文