在 ASP.Net Web Api 2 中使用 PUT 动词上传文件
Upload file using PUT verb in ASP.Net Web Api 2
我想公开一个 ASP.Net Web Api 2 操作,使用 HTTP PUT 动词上传文件。这与我们的 REST 模型一致,因为 API 代表一个远程文件系统(类似于 WebDAV,但真正简化),因此客户端选择资源名称(因此 PUT 是理想的,而 POST 不是合乎逻辑的选择)。
Web Api 文档描述了 how to upload files using multipart/form-data forms,但没有描述如何使用 PUT 方法。
你会用什么来测试这样的 API(HTML 多部分形式不允许 PUT 动词)?服务器实现看起来像 the web api documentation 中描述的多部分实现(使用 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);
}
}
经过几次测试,我作为示例发布的服务器端代码似乎是正确的。这是一个示例,从任何 authentication/authorization/error 处理代码中删除:
[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>
我想公开一个 ASP.Net Web Api 2 操作,使用 HTTP PUT 动词上传文件。这与我们的 REST 模型一致,因为 API 代表一个远程文件系统(类似于 WebDAV,但真正简化),因此客户端选择资源名称(因此 PUT 是理想的,而 POST 不是合乎逻辑的选择)。
Web Api 文档描述了 how to upload files using multipart/form-data forms,但没有描述如何使用 PUT 方法。
你会用什么来测试这样的 API(HTML 多部分形式不允许 PUT 动词)?服务器实现看起来像 the web api documentation 中描述的多部分实现(使用 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);
}
}
经过几次测试,我作为示例发布的服务器端代码似乎是正确的。这是一个示例,从任何 authentication/authorization/error 处理代码中删除:
[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>