ASP.Net Web Api 2中使用PUT方法上传文件

9
我希望使用HTTP PUT动词来上传文件,暴露一个ASP.Net Web Api 2的操作。这与我们的REST模型一致,因为API代表了一个远程文件系统(类似于WebDAV,但真正简化了),因此客户端选择资源名称(因此PUT是理想的选择,POST不是逻辑上的选择)。Web Api文档描述了如何使用multipart/form-data表单上传文件,但没有描述如何使用PUT方法进行操作。您会使用什么来测试这样的API(HTML multipart表单不允许PUT动词)?服务器实现是否像Web Api文档中描述的multipart实现一样(使用MultipartStreamProvider),还是应该像这样:
[HttpPut]
public async Task<HttpResponseMessage> PutFile(string resourcePath)
{
    Stream fileContent = await this.Request.Content.ReadAsStreamAsync();
    bool isNew = await this._storageManager.UploadFile(resourcePath, fileContent);
    if (isNew)
    {
        return this.Request.CreateResponse(HttpStatusCode.Created);
    }
    else
    {
        return this.Request.CreateResponse(HttpStatusCode.OK);
    }
}
1个回答

11

经过几次测试,我发现我发布的服务器端代码示例是正确的。这是一个示例,已经剥离了任何身份验证/授权/错误处理代码:

经过几次测试,似乎我发布的作为示例的服务器端代码是正确的。以下是一个示例,已经剥离了任何身份验证/授权/错误处理代码:

[HttpPut]
[Route(@"api/storage/{*resourcePath?}")]
public async Task<HttpResponseMessage> PutFile(string resourcePath = "")
{
    // Extract data from request
    Stream fileContent = await this.Request.Content.ReadAsStreamAsync();
    MediaTypeHeaderValue contentTypeHeader = this.Request.Content.Headers.ContentType;
    string contentType =
        contentTypeHeader != null ? contentTypeHeader.MediaType : "application/octet-stream";

    // Save the file to the underlying storage
    bool isNew = await this._dal.SaveFile(resourcePath, contentType, fileContent);

    // Return appropriate HTTP status code
    if (isNew)
    {
        return this.Request.CreateResponse(HttpStatusCode.Created);
    }
    else
    {
        return this.Request.CreateResponse(HttpStatusCode.OK);
    }
}

一个简单的控制台应用就足以测试它(使用 Web Api 客户端库):

using (var fileContent = new FileStream(@"C:\temp\testfile.txt", FileMode.Open))
using (var client = new HttpClient())
{
    var content = new StreamContent(fileContent);
    content.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
    client.BaseAddress = new Uri("http://localhost:81");
    HttpResponseMessage response =
        await client.PutAsync(@"/api/storage/testfile.txt", content);
}

编辑日期:2018-05-09:

此评论所述,如果您计划支持带有扩展名的文件名({filename}.{extension})而不强制客户端附加尾随斜杠,则需要修改您的web.config将IIS绑定到您的Web API应用程序以处理这些文件类型,因为默认情况下IIS将使用静态文件处理程序来处理看起来像文件名的内容(即URL中最后一个路径段包含点)。我的system.webServer部分如下:

<system.webServer>
    <handlers>
      <!-- Clear all handlers, prevents executing code file extensions or returning any file contents. -->
      <clear />
      <!-- Favicon static handler. -->
      <add name="FaviconStaticFile" path="/favicon.ico" verb="GET" modules="StaticFileModule" preCondition="integratedMode" resourceType="File" requireAccess="Read" />
      <!-- By default, only map extensionless URLs to ASP.NET -->
      <!-- (the "*." handler mapping is a special syntax that matches extensionless URLs) -->
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <!-- API endpoints must handle path segments including a dot -->
      <add name="ExtensionIncludedUrlHandler-Integrated-4.0" path="/api/storage/*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>
</system.webServer>

请注意,由于各种限制,某些文件名可能无法使用。例如,您不能将路径段命名为 . .. ,因为RFC要求替换它,Azure托管服务不允许冒号作为路径段的最后一个字符,而IIS默认禁止一组字符。

您还可以增加IIS / ASP.NET文件上传大小限制:

<!-- Path specific settings -->
<location path="api/storage">
  <system.web>
    <httpRuntime maxRequestLength="200000000" />
  </system.web>
  <system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="200000000" />
      </requestFiltering>
    </security>
    </system.webServer>
</location>

1
看看如何编写适当的单元测试,而不是依赖于运行HTTP服务器,这将很有趣。 - James
1
我在让这个工作起来时遇到了很多麻烦,因为我一直收到404错误。原来你可能需要更改web.config以接受形式为{filename}.{extension}的文件名。有关详细信息,请参见此Stackoverflow问题:https://dev59.com/IWEi5IYBdhLWcg3wuuYk - Simon Elms

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接