2014-10-18 2 views
5

Tworzę punkt końcowy oddzwaniający dla trafienia API strony trzeciej. Dzwoniący będzie używał do tego danych POST wieloczęściowy formularz.Serialize alternatywne nazwy właściwości z formularza w POST

coś takiego:

public SomeApiController : ApiController { 
    public AModel Post(AModel input) { 
    return input; //for demonstration 
    } 
} 

Niektóre pola będzie zamieszczać mieć kreski w nazwie, która nie może być rzeczywista nazwa właściwości .NET. Tak więc użyłem [DataContract] i [DataMember (name = "bla")] aby zdefiniować reguły serializacji.

Model:

//input model class 
[DataContract] 
public class AModel { 
    [DataMember] 
    public string NormalProperty {get; set;} //value set appropriately 
    [DataMember(Name="abnormal-property")] 
    public string AbnormalProperty {get; set;} //always null (not serializing) 
} 

Przy standardowych stanowisk XML i JSON, to działa prawidłowo. Normal i AbnormalProperty są ustawione i mogę nosić o mojej firmie.

Jednak z każdym wariantem danych formularzy (form-data, multiplart/form-data, x-urlencoded-form-dane, AbnormalProperty nie prawidłowo deserializowania do modelu, i zawsze będzie zerowy.

Czy istnieje dyrektywa mi brakuje albo coś?

Odpowiedz

0

Po wielu uderzeniach głowy mniej więcej połączono dwie rzeczy.

W przypadku formularzy zakodowanych za pomocą adresu URL, podążamy za przykładem The Zen Coder i działa bezbłędnie.

Jednak w przypadku tradycyjnych wieloczęściowych formularzy, które są przesyłane strumieniowo na serwer (mogą zawierać dane pliku), stworzyliśmy proste rozwiązanie do odczytywania kluczy/wartości z żądania, a następnie serializowano ręcznie.

W naszym szczególnym przypadku użycia, nie musimy się martwić o nadejście plików lub cokolwiek, więc możemy po prostu założyć, że wszystko jest ciągiem i czy wykonujemy pracę z serializacją. Jednak może być rozsądnie dodać proste sprawdzenie nagłówka ContentDisposition dla rzeczywistych plików.

przykład:

using System; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Net.Http; 
using System.Threading.Tasks; 
using System.Web.Http; 

namespace WebApplication1.Controllers 
{ 
    public class ValuesController : ApiController 
    { 
     public async Task<Dictionary<string,string>> Post() 
     { 
      if (!Request.Content.IsMimeMultipartContent()) 
       throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType); 
      var provider = new MultipartMemoryStreamProvider(); 
      var formData = new Dictionary<string,string>(); 
      try 
      { 
       await Request.Content.ReadAsMultipartAsync(provider); 
       foreach (var item in provider.Contents) 
       { 
        formData.Add(item.Headers.ContentDisposition.Name.Replace("\"",""), await item.ReadAsStringAsync()); 
       } 

       return formData; 
      } 
      catch (Exception e) 
      { 
       throw new HttpResponseException(HttpStatusCode.InternalServerError); 
      } 
     }  
    } 
} 
4

I hav e wypróbował twój przykład i mój wniosek jest taki, że DefaultModelBinder w ASP.NET MVC nie obsługuje tego nazewnictwa zmiennych POST.

Oczywistym rozwiązaniem nie jest użycie kreski w nazwach.

Jeśli nie jest to opcja, można zaimplementować własny segregator modelu dla tego konkretnego modelu, aby obsłużyć nieprawidłowe nazwy wysyłane do kontrolera MVC. Oto przykład model niestandardowy spoiwem:

public class AModelDataBinder : DefaultModelBinder 
{ 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     if (bindingContext.ModelType == typeof(AModel)) 
     { 
      var request = controllerContext.HttpContext.Request; 

      string normal = request.Form.Get("normalproperty"); 
      string abnormal = request.Form.Get("abnormal-property"); 

      return new AModel 
      { 
       NormalProperty = normal, 
       AbnormalProperty = abnormal 
      }; 
     } 

     return base.BindModel(controllerContext, bindingContext); 
    } 
} 

Wtedy trzeba zarejestrować ten niestandardowy spoiwo w Global.asax:

ModelBinders.Binders.Add(typeof(AModel), new AModelDataBinder()); 

I wreszcie można użyć niestandardowego wiążącej w swojej kontroler:

[HttpPost] 
public ActionResult Index([ModelBinder(typeof(AModelDataBinder))]AModel input) 
{ 
    // Handle POST 

    return View(); 
}