html 用于WebApi的MediaTypeFormatter,用于包含文件上载的多部分/表单数据

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了html 用于WebApi的MediaTypeFormatter,用于包含文件上载的多部分/表单数据相关的知识,希望对你有一定的参考价值。

using System.ComponentModel.DataAnnotations;
using System.Web;

namespace WebApiFileUpload.Models
{
    /// <summary>
    /// This is an API viewmodel showing how to accept a file upload via multipart/form-data
    /// </summary>
    public class UploadRequestViewModel
    {
        [Required]
        public string Title { get; set; }

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

        [Required]
        public HttpPostedFileBase File { get; set; }
    }
}
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebApiFileUpload.Models;

namespace WebApiFileUpload.Controllers
{
    /// <summary>
    /// This is an example controller showing how to accept file uploads. 
    /// </summary>
    public class UploadController : ApiController
    {
        // simply accept the viewmodel as usual
        public IHttpActionResult Post(UploadRequestViewModel model)
        {
            // provide validation result if not valid
            if (!ModelState.IsValid)
            {
                var response = Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                return ResponseMessage(response);
            }

            // show some details about the upload as result
            return Content(HttpStatusCode.OK, new
            {
                Status = "success",
                Title = model.Title,
                Description = model.Description,
                FileName = model.File.FileName,
                ContentLength = model.File.ContentLength,
                ContentType = model.File.ContentType
            });
        }
    }
}
using System.IO;
using System.Web;

namespace WebApiFileUpload.Utils
{
    /// <summary>
    /// Represents a file that has uploaded by a client via multipart/form-data. 
    /// </summary>
    public class HttpPostedFileMultipart : HttpPostedFileBase
    {
        private readonly MemoryStream _fileContents;

        public override int ContentLength => (int)_fileContents.Length;
        public override string ContentType { get; }
        public override string FileName { get; }
        public override Stream InputStream => _fileContents;

        /// <summary>
        /// Initializes a new instance of the <see cref="HttpPostedFileMultipart"/> class. 
        /// </summary>
        /// <param name="fileName">The fully qualified name of the file on the client</param>
        /// <param name="contentType">The MIME content type of an uploaded file</param>
        /// <param name="fileContents">The contents of the uploaded file.</param>
        public HttpPostedFileMultipart(string fileName, string contentType, byte[] fileContents)
        {
            FileName = fileName;
            ContentType = contentType;
            _fileContents = new MemoryStream(fileContents);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Controllers;
using System.Web.Http.ModelBinding;
using System.Web.Http.ModelBinding.Binders;
using System.Web.Http.Validation;
using System.Web.Http.Validation.Providers;
using System.Web.Http.ValueProviders.Providers;

namespace WebApiFileUpload.Utils
{
    /// <summary>
    /// Represents the <see cref="MediaTypeFormatter"/> class to handle multipart/form-data. 
    /// </summary>
    public class FormMultipartEncodedMediaTypeFormatter : MediaTypeFormatter
    {
        private const string SupportedMediaType = "multipart/form-data";

        /// <summary>
        /// Initializes a new instance of the <see cref="FormMultipartEncodedMediaTypeFormatter"/> class.
        /// </summary>
        public FormMultipartEncodedMediaTypeFormatter()
        {
            SupportedMediaTypes.Add(new MediaTypeHeaderValue(SupportedMediaType));
        }

        public override bool CanReadType(Type type)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));
            return true;
        }

        public override bool CanWriteType(Type type)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));
            return false;
        }

        public override async Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
        {
            if (type == null) throw new ArgumentNullException(nameof(type));
            if (readStream == null) throw new ArgumentNullException(nameof(readStream));

            try
            {
                // load multipart data into memory 
                var multipartProvider = await content.ReadAsMultipartAsync();
                // fill parts into a ditionary for later binding to model
                var modelDictionary = await ToModelDictionaryAsync(multipartProvider);
                // bind data to model 
                return BindToModel(modelDictionary, type, formatterLogger);
            }
            catch (Exception e)
            {
                if (formatterLogger == null)
                {
                    throw;
                }
                formatterLogger.LogError(string.Empty, e);
                return GetDefaultValueForType(type);
            }
        }

        private async Task<IDictionary<string, object>> ToModelDictionaryAsync(MultipartMemoryStreamProvider multipartProvider)
        {
            var dictionary = new Dictionary<string, object>();

            // iterate all parts 
            foreach (var part in multipartProvider.Contents)
            {
                // unescape the name 
                var name = part.Headers.ContentDisposition.Name.Trim('"');

                // if we have a filename, we treat the part as file upload,
                // otherwise as simple string, model binder will convert strings to other types. 
                if (!string.IsNullOrEmpty(part.Headers.ContentDisposition.FileName))
                {
                    // set null if no content was submitted to have support for [Required]
                    if (part.Headers.ContentLength.GetValueOrDefault() > 0)
                    {
                        dictionary[name] = new HttpPostedFileMultipart(
                            part.Headers.ContentDisposition.FileName.Trim('"'),
                            part.Headers.ContentType.MediaType,
                            await part.ReadAsByteArrayAsync()
                        );
                    }
                    else
                    {
                        dictionary[name] = null;
                    }
                }
                else
                {
                    dictionary[name] = await part.ReadAsStringAsync();
                }
            }

            return dictionary;
        }


        private object BindToModel(IDictionary<string, object> data, Type type, IFormatterLogger formatterLogger)
        {
            if (data == null) throw new ArgumentNullException(nameof(data));
            if (type == null) throw new ArgumentNullException(nameof(type));

            using (var config = new HttpConfiguration())
            {
                // if there is a requiredMemberSelector set, use this one by replacing the validator provider
                var validateRequiredMembers = RequiredMemberSelector != null && formatterLogger != null;
                if (validateRequiredMembers)
                {
                    config.Services.Replace(typeof(ModelValidatorProvider), new RequiredMemberModelValidatorProvider(RequiredMemberSelector));
                }

                // create a action context for model binding
                var actionContext = new HttpActionContext
                {
                    ControllerContext = new HttpControllerContext
                    {
                        Configuration = config,
                        ControllerDescriptor = new HttpControllerDescriptor
                        {
                            Configuration = config
                        }
                    }
                };

                // create model binder context 
                var valueProvider = new NameValuePairsValueProvider(data, CultureInfo.InvariantCulture);
                var metadataProvider = actionContext.ControllerContext.Configuration.Services.GetModelMetadataProvider();
                var metadata = metadataProvider.GetMetadataForType(null, type);
                var modelBindingContext = new ModelBindingContext
                {
                    ModelName = string.Empty,
                    FallbackToEmptyPrefix = false,
                    ModelMetadata = metadata,
                    ModelState = actionContext.ModelState,
                    ValueProvider = valueProvider
                };

                // bind model 
                var modelBinderProvider = new CompositeModelBinderProvider(config.Services.GetModelBinderProviders());
                var binder = modelBinderProvider.GetBinder(config, type);
                var haveResult = binder.BindModel(actionContext, modelBindingContext);

                // log validation errors 
                if (formatterLogger != null)
                {
                    foreach (var modelStatePair in actionContext.ModelState)
                    {
                        foreach (var modelError in modelStatePair.Value.Errors)
                        {
                            if (modelError.Exception != null)
                            {
                                formatterLogger.LogError(modelStatePair.Key, modelError.Exception);
                            }
                            else
                            {
                                formatterLogger.LogError(modelStatePair.Key, modelError.ErrorMessage);
                            }
                        }
                    }
                }

                return haveResult ? modelBindingContext.Model : GetDefaultValueForType(type);
            }
        }
    }
}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />    
    <title>File Upload example</title>
    <link href="/Content/bootstrap.css" rel="stylesheet" />
</head>
<body>
    <form action="api/Upload" method="post">
        <div class="form-group">
            <label for="SiteId">Site Id</label>
            <input type="number" class="form-control" id="SiteId" name="SiteId" placeholder="Site Id" />
        </div>
        <div class="form-group">
            <label for="StartDate">Start Date</label>
            <input class="form-control" id="StartDate" name="StartDate" placeholder="Start Date" />
        </div>
        <div class="form-group">
            <label for="Zulu">File</label>
            <input class="form-control" id="Zulu" name="Zulu" placeholder="Zulu" />
        </div>
        <button class="btn btn-primary" type="submit">Send</button>
    </form>
</body>
</html>

以上是关于html 用于WebApi的MediaTypeFormatter,用于包含文件上载的多部分/表单数据的主要内容,如果未能解决你的问题,请参考以下文章

没有 MediaTypeFormatter 可用于从 asp.net mvc webapi 中媒体类型为“text/html”的内容中读取“IEnumerable`1”类型的对象

如何在 MVC 控制器中通过 WebApi 从 HTML 页面发布数据

WebAPI - 属性路由 POST 不适用于 WebAPI Cors?

Python机器学习Web Api

通过 Angular 调用时,Windows 身份验证不适用于 WebAPI

webapi token和basic的区别