【问题标题】:ASP.NET Web API controller can't handle dynamic objects?ASP.NET Web API 控制器不能处理动态对象?
【发布时间】:2015-12-04 21:11:48
【问题描述】:

在我的代码中,我有一个基类 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 中的 This controller 在动态作为输入参数时效果很好。

【问题讨论】:

    标签: model-binding asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    嗯,我可以使用 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}]
    

    它成功了....

    【讨论】:

      【解决方案2】:

      似乎有些人认为即使在 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);
      }
      

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

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

      【讨论】:

      • 非常感谢您的出色解释,对于一个模糊的问题,我深表歉意。如果我想要一个基类,一个抽象的 User,然后是一个继承 User 类的 Administrator 类,如果我想使用 API 控制器来保存所有用户,你的建议是什么?它是自定义模型绑定器吗?另一个问题是UpdateModel,它在api控制器中不存在,那么它是如何更新现有对象的呢?
      • @Marcus,在 ASP.NET Web API 中,您可以编写自定义 MediaTypeFormatter 来完成此任务。这是使用 JSON.NET 作为序列化程序的an example。使用 JSON.NET,您可以编写一个custom JsonConverter,它允许您序列化抽象类。
      • 我的问题更多是关于保存和更新从 User 类继承的类型的 User 。看这个例子pastebin.com/sRGW62yw当然输入参数不能是User,因为它没有属性LastName,然后它不会绑定它,因为它不存在。这就是我尝试使用动态输入参数的原因,因为我唯一知道的是输入参数扩展了 User 类,我想保存扩展类中的所有数据。我希望你明白我在这里想要做什么。
      • @Marcus,你可以写一个自定义的MediaTypeFormatter 来处理这种情况。
      • 好的,我试试看。再次感谢您的帮助!
      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-28
        • 2021-05-09
        • 2012-09-24
        • 2023-02-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多