获取Content-Disposition参数
如何使用WebClient获取从WebAPI控制器返回的Content-Disposition参数?
WebApi控制器
[Route("api/mycontroller/GetFile/{fileId}")] public HttpResponseMessage GetFile(int fileId) { try { var file = GetSomeFile(fileId) HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); response.Content = new StreamContent(new MemoryStream(file)); response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); response.Content.Headers.ContentDisposition.FileName = file.FileOriginalName; /********* Parameter *************/ response.Content.Headers.ContentDisposition.Parameters.Add(new NameValueHeaderValue("MyParameter", "MyValue")); return response; } catch(Exception ex) { return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex); } }
客户
void DownloadFile() { WebClient wc = new WebClient(); wc.DownloadDataCompleted += wc_DownloadDataCompleted; wc.DownloadDataAsync(new Uri("api/mycontroller/GetFile/18")); } void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) { WebClient wc=sender as WebClient; // Try to extract the filename from the Content-Disposition header if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"])) { string fileName = wc.ResponseHeaders["Content-Disposition"].Substring(wc.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 10).Replace("\"", ""); //FileName ok /****** How do I get "MyParameter"? **********/ } var data = e.Result; //File OK }
我正在从WebApi控制器返回一个文件,我在响应内容标题中附加了文件名,但我还想返回一个aditional值。
在客户端我能够获取文件名,但我如何获得aditional参数?
如果您使用的是.NET 4.5或更高版本,请考虑使用System.Net.Mime.ContentDisposition类:
string cpString = wc.ResponseHeaders["Content-Disposition"]; ContentDisposition contentDisposition = new ContentDisposition(cpString); string filename = contentDisposition.FileName; StringDictionary parameters = contentDisposition.Parameters; // You have got parameters now
编辑:
否则,您需要根据其规范解析Content-Disposition标头。
这是一个执行解析的简单类,接近规范:
class ContentDisposition { private static readonly Regex regex = new Regex( "^([^;]+);(?:\\s*([^=]+)=((?\"?)[^\"]*\\k);?)*$", RegexOptions.Compiled ); private readonly string fileName; private readonly StringDictionary parameters; private readonly string type; public ContentDisposition(string s) { if (string.IsNullOrEmpty(s)) { throw new ArgumentNullException("s"); } Match match = regex.Match(s); if (!match.Success) { throw new FormatException("input is not a valid content-disposition string."); } var typeGroup = match.Groups[1]; var nameGroup = match.Groups[2]; var valueGroup = match.Groups[3]; int groupCount = match.Groups.Count; int paramCount = nameGroup.Captures.Count; this.type = typeGroup.Value; this.parameters = new StringDictionary(); for (int i = 0; i < paramCount; i++ ) { string name = nameGroup.Captures[i].Value; string value = valueGroup.Captures[i].Value; if (name.Equals("filename", StringComparison.InvariantCultureIgnoreCase)) { this.fileName = value; } else { this.parameters.Add(name, value); } } } public string FileName { get { return this.fileName; } } public StringDictionary Parameters { get { return this.parameters; } } public string Type { get { return this.type; } } }
然后你可以这样使用它:
static void Main() { string text = "attachment; filename=\"fname.ext\"; param1=\"A\"; param2=\"A\";"; var cp = new ContentDisposition(text); Console.WriteLine("FileName:" + cp.FileName); foreach (DictionaryEntry param in cp.Parameters) { Console.WriteLine("{0} = {1}", param.Key, param.Value); } } // Output: // FileName:"fname.ext" // param1 = "A" // param2 = "A"
使用此类时唯一应该考虑的是它在没有双引号的情况下不处理参数(或文件名)。
编辑2:
它现在可以处理没有引号的文件名。
您可以使用以下框架代码解析内容处置:
var content = "attachment; filename=myfile.csv"; var disposition = ContentDispositionHeaderValue.Parse(content);
然后从处置实例中取出碎片。
disposition.FileName disposition.DispositionType
价值就在那里我只需要提取它:
Content-Disposition标头返回如下:
Content-Disposition = attachment; filename="C:\team.jpg"; MyParameter=MyValue
所以我只是使用了一些字符串操作来获取值:
void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) { WebClient wc=sender as WebClient; // Try to extract the filename from the Content-Disposition header if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"])) { string[] values = wc.ResponseHeaders["Content-Disposition"].Split(';'); string fileName = values.Single(v => v.Contains("filename")) .Replace("filename=","") .Replace("\"",""); /********** HERE IS THE PARAMETER ********/ string myParameter = values.Single(v => v.Contains("MyParameter")) .Replace("MyParameter=", "") .Replace("\"", ""); } var data = e.Result; //File ok }