【问题标题】:Image Upload using MVC API POST Multipart form使用 MVC API POST Multipart 表单上传图片
【发布时间】:2014-01-30 11:30:09
【问题描述】:

我的观点:-

   <form class="commentform commentright"   enctype="multipart/form-data" >
                <textarea class="simpleta required" name="Body" placeholder="Discuss this vehicle with other members of Row52."></textarea>
                <input type="file" id="fileuploadfield" name="fileuploadfield"/>
                <input type="submit" value="Submit" class="btn btn-inverse btn-small"/>
                <input type="hidden" name="ParentId" value="0"/>
                <input type="hidden" name="VehicleId" value="@Model.VehicleId"/>
                <span class="commentcount"><span class="numberofcomments">@Model.Count</span>@count</span>
                <div class="feedback"></div>
                <img id="img" src="" />

            </form>

jQuery :-

 submitComment: function (form, type) {
            var self = this;
            var $this = $(form);
            var formData = $this.serialize();
            var $message = $this.find('.feedback');

            $message.hide();
            $message.html('');

            var val = validation({ $form: $this });
            if (val.checkRequired()) {
                $this.indicator({ autoStart: false, minDuration: 100 });
                $this.indicator('start');
                var files = $("#fileuploadfield").get(0).files;

                if (files.length > 0) {
                    if (window.FormData !== undefined) {
                        var data = new FormData();
                        for (var i = 0; i < files.length; i++) {
                            data.append("file" + i, files[i]);

                        }
                    }
                    else {
                        alert("This browser doesn't support HTML5 multiple file uploads!");
                    }
                }
                else {
                    alert("This");
                }

                $.ajax('/api/v2/comment/Post/', {
                    type: 'POST',
                    contentType: 'multipart/form-data',
                        // I have also use contentType: false,
                    processData: false,
                    data: formData
                }).done(function (d) {

控制器:-

 public Task<HttpResponseMessage> Post()
        {
            var provider = new MultipartMemoryStreamProvider();
            var task1 = Request.Content.ReadAsMultipartAsync(provider);
            var userId = User.Id;

            return task1.Then(providerResult =>
                {
                    var file = GetFileContent(providerResult);
                    var task2 = file.ReadAsStreamAsync();
                    string originalFileName = file.Headers.ContentDisposition.FileName.Replace("\"", "");
                    string extension = Path.GetExtension(originalFileName);
                    string fileName = Guid.NewGuid().ToString() + extension;

                    return task2.Then(stream =>
                        {
                            if (stream.Length > 0)
                            {
                                var kernel = WindsorContainerFactory.Create(KernelState.Thread, ConfigurationState.Web);
                                CloudBlobContainer container = GetContainer();

                                var userRepo = kernel.Resolve<IUserRepository>();
                                var logger = kernel.Resolve<ILogger>();
                                logger.Fatal("Original File Name: " + originalFileName);
                                logger.Fatal("Extension: " + extension);
                                logger.Fatal("File Name: " + fileName);
                                var user = userRepo.FirstOrDefault(x => x.Id == userId);
                                var path = CreateImageSize(stream, 500, fileName, userId, container, logger);
                                if (user != null)
                                {
                                    user.AvatarOriginalFileName = fileName;
                                    user.AvatarOriginalAbsolutePath =
                                        ConfigurationManager.AppSettings["CdnUserEndpointUrl"] + path;
                                    user.AvatarOriginalRelativePath = path;
                                    user.AvatarCroppedAbsolutePath = "";
                                    user.AvatarCroppedFileName = "";
                                    user.AvatarCroppedRelativePath = "";
                                    userRepo.Update(user);
                                }
                                else
                                {
                                    Logger.Error("User is null.  Id: " + userId.ToString());
                                }

                                kernel.Release(userRepo);
                                kernel.Release(logger);
                                kernel.Dispose();
                            }

                            var response = Request.CreateResponse(HttpStatusCode.Moved);
                            response.Headers.Location = new Uri("/Account/Avatar", UriKind.Relative);
                            return response;
                        });
                });
        }

以下错误获取:- “提供的'HttpContent'实例无效。它没有以'multipart/'开头的内容类型标头。参数名称:内容”

【问题讨论】:

  • 你能显示你的Task.Then扩展的代码吗?
  • @Noseratio 我已经把控制器的所有代码都放到了 public Task Post().
  • @Noseratio 代码为 Then 。 public static Task Then(this Task task, Func> continuation, CancellationToken cancellationToken = null, bool runSynchronously = false);但我有第三方的 dll
  • 我确信第 3 方 DLL 使用了我在回答中链接的 Stephen Toub 的相同代码。只需使用我展示的修改版本即可。 TaskScheduler.FromCurrentSynchronizationContext() 对于使 HttpContent 与 ContinueWith 一起流动至关重要。阅读this,了解更多关于AspNetSynchronizationContext的信息。
  • 您是否以其他方式解决了这个问题?如果是这样,我很想知道如何。

标签: asp.net-mvc file-upload task-parallel-library multipartform-data


【解决方案1】:

.NET 框架中没有标准的Task.Then 方法,我在您发布的代码中找不到任何实现细节。我假设它是从这里拍摄的:

Processing Sequences of Asynchronous Operations with Tasks

如果是这种情况,您可能会在 Task.Then lambdas 中丢失 AspNetSynchronizationContext 上下文,因为在没有适当同步上下文的情况下,延续可能发生在不同的 ASP.NET 池线程上。这可以解释为什么HttpContent 变得无效。

尝试像这样更改Task.Then 的实现:

public static Task<T2> Then<T1, T2>(this Task<T1> first, Func<T1, Task<T2>> next) 
{ 
    if (first == null) throw new ArgumentNullException("first"); 
    if (next == null) throw new ArgumentNullException("next");

    var tcs = new TaskCompletionSource<T2>(); 
    first.ContinueWith(delegate 
    { 
        if (first.IsFaulted) tcs.TrySetException(first.Exception.InnerExceptions); 
        else if (first.IsCanceled) tcs.TrySetCanceled(); 
        else 
        { 
            try 
            { 
                var t = next(first.Result); 
                if (t == null) tcs.TrySetCanceled(); 
                else t.ContinueWith(delegate 
                { 
                    if (t.IsFaulted) tcs.TrySetException(t.Exception.InnerExceptions); 
                    else if (t.IsCanceled) tcs.TrySetCanceled(); 
                    else tcs.TrySetResult(t.Result); 
                }, TaskScheduler.FromCurrentSynchronizationContext()); 
            } 
            catch (Exception exc) { tcs.TrySetException(exc); } 
        } 
    }, TaskScheduler.FromCurrentSynchronizationContext()); 
    return tcs.Task; 
}

请注意现在如何使用 TaskScheduler.FromCurrentSynchronizationContext() 安排延续。

理想情况下,如果您可以使用 .NET 4.5,您应该使用 async/await:Using Asynchronous Methods in ASP.NET 4.5。这样,线程的同步上下文会自动捕获await 延续。

以下可能有助于移植: Implementing Then with Await.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-24
    • 2022-07-29
    • 2015-10-11
    • 1970-01-01
    • 2016-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多