2012-02-23 1 views
3

В моем коде у меня есть базовый класс Foo и все мои объекты наследуются от объекта Foo. Так скажем, у меня есть класс, как этотКонтроллер API ASP.NET не может обрабатывать динамические объекты?

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

Я пытался использовать ApiControllers поставил метод с динамическим, но я получаю эту ошибку http://paste2.org/p/1914054

Это код, я использую в ApiController

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

Если я использую обычный контроллер, я могу использовать динамический для публикации данных. Можно ли добавить, чтобы контроллер api работал с динамическим или мне нужно было создать собственное связующее устройство?

Он видит, что некоторые думают, что даже в MVC 3 входные параметры не могут быть динамическими, но это не так, и именно поэтому я задаю этот вопрос. This controller в MVC 3 отлично работает с динамическим параметром ввода.

ответ

1

Он видит, как некоторые думают, что даже в 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.

+1

Большое спасибо за отличное объяснение, и я прошу прощения за пугающий вопрос. Если бы я хотел иметь базовый класс, пользователь, который является абстрактным, а затем классом администратора, который наследует класс User, какова ваша рекомендация, если я хотел бы использовать контроллер API для сохранения всех пользователей? Является ли это обычным связующим устройством? Другой вопрос - UpdateModel, это не существует в контроллере api, так как это означает обновление существующего объекта? – Marcus

+1

@Marcus, в ASP.NET Web API вы можете написать пользовательский 'MediaTypeFormatter' для достижения этой задачи. Вот [пример] (http://code.msdn.microsoft.com/Using-JSONNET-with-ASPNET-b2423706), который использует JSON.NET в качестве сериализатора. А с JSON.NET вы можете написать ['custom JsonConverter'] (http://stackoverflow.com/a/8031283/29407), который позволит вам сериализовать абстрактные классы. –

+0

Мой вопрос больше о сохранении и обновлении пользователя, который имеет тип, наследующий от класса User. Посмотрите на этот пример http://pastebin.com/sRGW62yw Конечно, входной параметр не может быть пользователем, поскольку он не имеет свойства LastName, и тогда он не будет связывать его, потому что он не существует. Вот почему я попытался использовать динамический входной параметр, потому что единственное, что я знаю, это то, что входной параметр расширяет класс User, и я хочу сохранить все данные из расширенного класса. Надеюсь, вы понимаете, что я здесь делаю. – Marcus

3

Хм, я был в состоянии только сделать это с помощью метода Web API ASP.NET:

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}] 

И это сработало ....

+0

Он работал для меня также в веб-API из ASP .Net MVC 4 –

0

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 

     });