Модель POST в MVC из сервисного или консольного приложения - PullRequest
0 голосов
/ 04 июня 2019

У меня есть страница бритвы, которая отправляет модель представления, содержащую файл с некоторой метаинформацией, в веб-службу (.net core 2.2 mvc).Я пытаюсь сделать то же самое из консольного приложения или службы Windows.У меня есть рабочее решение, но это выглядит немного неуклюже.Я ищу лучшее / более универсальное решение.

Модель:

public class UploadModel
{
    [JsonIgnore]
    public IFormFile File { get; set; }

    [FromForm]
    public string Description { get; set; }

    // inspired by https://stackoverflow.com/questions/44979737/model-binding-for-multipart-form-data-file-json-post-in-asp-net-core-1-1
    [ModelBinder(BinderType = typeof(FormDataJsonBinder))]
    public List<string> Attributes { get; set; }

}

Метод контроллера:

[HttpPost]
public void Post([FromForm] UploadModel value)
{
   using (var stream = new FileStream(@"C:\Tmp\MyNewFile.pdf", FileMode.Create))
   {
       value.File.CopyTo(stream);
   }
}

Функция загрузки (используется вконсольное приложение для отладки):

// inspired by https://stackoverflow.com/questions/49229368/post-multipart-form-data-in-c-sharp-httpclient-4-5
public static async Task<bool> Upload(UploadModel model)
{
    using (var client = new HttpClient())
    {
        try
        {
            var formDataContent = new MultipartFormDataContent();

            // add the file here - won't be added automatically since it is marked [JsonIgnore] in the model
            var fileContent = new StreamContent(model.File.OpenReadStream())
            {
               Headers =
               {
                  ContentLength = model.File1.Length,
                  ContentType = new MediaTypeHeaderValue(model.File.ContentType)
               }
            };
            formDataContent.Add(fileContent, "File", model.File.FileName);          

            // this part works but needs improvement:

            // add the remaining properties automatically
            dynamic jsonString = JsonConvert.SerializeObject(model);

            // iterate through jsonString  
            foreach (var item in JsonConvert.DeserializeObject(jsonString))
            {
               JProperty jp = item as JProperty;
               if (jp != null)
               {
                  formDataContent.Add(new StringContent(jp.Value.ToString()), jp.Name);
               }

            }

            var res = client.PostAsync(myControllerURL, formDataContent);
            res.Wait();

            return res.IsCompleted;
        }
        catch (Exception ex)
        {
            return false;
        }
    }
}

консольное приложение:

// just a mock up for debugging... 
static void Main(string[] args)
{
   UploadModel model = new UploadModel();

   using (var stream = File.OpenRead(@"C:\Tmp\MyFile.pdf"))
   {
        FormFile file = new FormFile(stream, 0, stream.Length, "MyFile", Path.GetFileName(stream.Name))
        {
           Headers = new HeaderDictionary(),
           ContentType = "application/octet-stream"
        };
        model.File = file;

        model.Description = "My text ...";
        model.Attributes= new List<string>() { "Attrib 1", "Attrib 2" };

        Upload(model);
   }
}

(асинхронные операции опущены для краткости).

Как я уже писал, это работает, ноSerializeObject / DeserializeObject не является наиболее эффективным способом, и я не уверен, что это будет работать с более сложными классами.

Я уже посмотрел на RestSharp, но не смог заставить это работать.

...