ResrSharp отправляет сложную модель в API, которую можно прочитать через FromForm - PullRequest
1 голос
/ 14 июня 2019

У меня очень простой метод в ASP.NET Core 2.2 WebAPI:

[HttpPut]
public async Task<IActionResult> Put([FromForm] SimpleRequest request, [FromForm] string param1)
{
    if (request.ExtraData == null) return BadRequest("Please send data");
    await Task.CompletedTask;
    return Ok("Works");
}

Моя модель выглядит так:

public class SimpleRequest
{
    [Required]
    public string UserId { get; set; }
    public RequestType? RequestType { get; set; }
    public DateTime Timestamp { get; set; }
    public bool Test { get; set; }
    public ExtraData ExtraData { get; set; }
}
public enum RequestType
{
    Simple,
    Complex,
}
public class ExtraData
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ulong Id { get; set; }
    public DateTime RDate { get; set; }
    public uint Nr { get; set; }
}

Когда я делаю запрос от Почтальона, моя модель привязывается правильно: enter image description here

Теперь я пытаюсь создать то же самое с помощью RestSharp. Когда я использую код ниже, он работает нормально:

var client = new RestClient("https://localhost:44325/api/values");
var request = new RestRequest(Method.PUT);

request.AddParameter("UserId", "Sample", ParameterType.GetOrPost);
request.AddParameter("RequestType", "Simple", ParameterType.GetOrPost);
request.AddParameter("Timestamp", DateTime.Now, ParameterType.GetOrPost);
request.AddParameter("Test", true, ParameterType.GetOrPost);
request.AddParameter("ExtraData.FirstName", "John", ParameterType.GetOrPost);
request.AddParameter("ExtraData.LastName", "Smith", ParameterType.GetOrPost);
request.AddParameter("ExtraData.Id", 1234, ParameterType.GetOrPost);
request.AddParameter("ExtraData.Nr", 1, ParameterType.GetOrPost);
request.AddParameter("ExtraData.RDate", DateTime.Now.AddDays(-2), ParameterType.GetOrPost);

request.AddParameter("param1", "YES", ParameterType.GetOrPost);

var response = client.Execute(request);

Но я хочу повторно использовать мои модели, потому что они совместно используются в отдельной DLL.

Я создаю свою модель так:

var model = new SimpleRequest
{
    UserId = "Sample",
    RequestType = RequestType.Simple,
    Timestamp = DateTime.Now,
    Test = true,
    ExtraData = new ExtraData
    {
        FirstName = "John",
        LastName = "Smith",
        Id = 1234,
        Nr = 1,
        RDate = DateTime.Now.AddDays(-2)
    }
};

но я не могу передать эту модель по запросу, чтобы ее можно было правильно десериализовать для моего объекта. Я пытался использовать request.AddJsonBody, но это не удалось.

Как правильно передать модель, как описано выше, через RestSharp? Как я должен сериализовать его (или добавить в качестве параметра), чтобы это работало.

1 Ответ

1 голос
/ 17 июня 2019

Для FromForm нам нужно отправить запрос через form-data или x-www-form-urlencoded. Вы можете реализовать свой собственный способ преобразования модели в x-www-form-urlencoded, например:

  1. Метод расширения для преобразования

    public static class RestSharpExtension
    {
            public static IDictionary<string, string> ToKeyValue(this object metaToken)
            {
            if (metaToken == null)
            {
                    return null;
            }
    
            JToken token = metaToken as JToken;
            if (token == null)
            {
                    return ToKeyValue(JObject.FromObject(metaToken));
            }
    
            if (token.HasValues)
            {
                    var contentData = new Dictionary<string, string>();
                    foreach (var child in token.Children().ToList())
                    {
                    var childContent = child.ToKeyValue();
                    if (childContent != null)
                    {
                            contentData = contentData.Concat(childContent)
                                                    .ToDictionary(k => k.Key, v => v.Value);
                    }
                    }
    
                    return contentData;
            }
    
            var jValue = token as JValue;
            if (jValue?.Value == null)
            {
                    return null;
            }
    
            var value = jValue?.Type == JTokenType.Date ?
                            jValue?.ToString("o", CultureInfo.InvariantCulture) :
                            jValue?.ToString(CultureInfo.InvariantCulture);
    
            return new Dictionary<string, string> { { token.Path, value } };
            }
    }
    
  2. Вариант использования

    public async Task<IActionResult> Index()
    {
        var model = new SimpleRequest
                            {
                                UserId = "Sample",
                                RequestType = RequestType.Simple,
                                Timestamp = DateTime.Now,
                                Test = true,
                                ExtraData = new ExtraData
                                {
                                    FirstName = "John",
                                    LastName = "Smith",
                                    Id = 1234,
                                    Nr = 1,
                                    RDate = DateTime.Now.AddDays(-2)
                                }
                            };
        var keyValueContent = model.ToKeyValue();
        keyValueContent.Add("param1", "YES");
        var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
        var urlEncodedString = await formUrlEncodedContent.ReadAsStringAsync();
    
        var client = new RestClient("http://localhost:51420/api/values/Put");
        var request = new RestRequest(Method.PUT);
    
        request.AddParameter("application/x-www-form-urlencoded", urlEncodedString, ParameterType.RequestBody);
    
        var response = client.Execute(request);
    }
    
...