У меня есть страница бритвы, которая отправляет модель представления, содержащую файл с некоторой метаинформацией, в веб-службу (.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, но не смог заставить это работать.