摘要從遠程Web服務
我需要檢索存儲在父應用程序從一個鏈接的子應用程序的客戶端附件返回附件。附件可通過Web服務調用在父應用程序中獲得 - 該應用程序返回標準FileContentResult,其內容類型爲「application/octet-stream」。我能想到的最好方法是通過WebRequest檢索,並將生成的響應流傳遞給FileStreamResult,儘管我有一些替代方法可用。
有沒有人知道是否在製作WebRequest時,一旦響應的第一部分被返回或緩衝後立即響應流變爲可用,所以我沒有得到響應,直到檢索到所有數據?
除了下面完整問題中列出的那些選項以外,還有其他選擇嗎? (除了將附件保留在兒童和父母的數據庫中 - 我真的不想這樣做,因爲我需要定期同步它們)。
TLDR版本
我有過一個RESTful網絡服務,通信的兩個相關應用。父應用程序維護可能具有附件的實體的集合。例如,一個請求可能有一個Excel電子表格作爲附件。實體及其附件存儲在數據庫中,使用與訪問請求相同的邏輯來控制對附件的訪問。也就是說,如果您無法查看請求,則無法下載附件。
在子應用程序中,我爲分配給特定機構的實體維護一些集成粘合劑 - 該應用程序用於在我們的董事會和每個董事會學校之間進行通信。我不想維護和同步整個實體/附件。我只想維護足夠的信息以允許我連接父應用程序中的Web服務,並獲取子應用程序的特定實例有權訪問的實體的詳細信息。
這適用於實體數據本身。數據量很小,子應用程序中的緩衝開銷並不會在訪問數據時出現明顯的延遲。如有必要,我可以在本地緩存數據以避免性能損失。
我擔心的是附件。我已經考慮了三種不同的機制來提供從子應用程序的客戶端訪問附件。
生成一次性使用令牌和關聯的url,允許客戶端直接從父應用程序下載附件。令牌生成Web服務調用將確保子應用程序的用戶應該有權訪問該附件。這樣做的缺點是你只能在客戶端點擊鏈接一次。再次點擊會導致錯誤,而不是獲取附件。
緩衝子應用中的附件。在這種情況下,我會提供一個控制器/操作以將附件下載到子應用程序中,然後調用Web服務方法來獲取附件並讓子應用程序將附件作爲FileContentResult發送。這消除了只能點擊鏈接一次的問題,但附件可能相當大,並且緩衝子應用程序中的數據可能會使下載附件的時間增加一倍,並且更糟糕的是,會在附件下載開始。
鏈接在子應用程序中,但直接將來自Web服務請求的流提供給FileStreamResult。對我來說,這看起來是FileStreamResult讀入塊的最佳選擇,而不是在將所有數據發送到客戶端之前都可用。我在這裏可以看到的唯一缺點是我無法直接處理WebResponse,因爲直到我的操作返回後纔會執行FileStreamResult。
以下是我對爲(2)和(3)API包裝代碼代碼:
private class ResponseModel<T> : IDisposable
{
public T Model { get; set; }
public WebResponse Response { get; set; }
private bool Disposed { get; set; }
private void Dispose(bool disposing)
{
if (!Disposed)
{
if (disposing)
{
((IDisposable)this.Response).Dispose();
}
Disposed = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
private ResponseModel<T> GetAttachmentResponse<T>(long id) where T : IDownloadModel, new()
{
var request = GetRequest(string.Format("{0}/api/getattachment/{1}/{2}", this.BaseUrl, this.Key, id));
var response = request.GetResponse();
var model = (T)Activator.CreateInstance<T>();
var contentDisposition = response.Headers["Content-Disposition"];
if (!string.IsNullOrEmpty(contentDisposition))
{
var filename = contentDisposition.Split(new[] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries)
.SingleOrDefault(s => s.StartsWith("filename", StringComparison.OrdinalIgnoreCase));
if (!string.IsNullOrEmpty(filename))
{
model.Name = filename.Split('=').Skip(1).FirstOrDefault();
}
}
if (string.IsNullOrEmpty(model.Name))
{
model.Name = "untitled";
}
return new ResponseModel<T> { Model = model, Response = response };
}
public FileDownloadModel GetAttachment(long id)
{
using (var response = GetAttachmentResponse<FileDownloadModel>(id))
{
var reader = new BinaryReader(response.Response.GetResponseStream());
response.Model.Content = reader.ReadBytes((int)response.Response.ContentLength);
return response.Model;
}
}
public FileStreamDownloadModel GetAttachmentStream(long id)
{
// since we're returning the stream, we can't dispose of the response when done.
var response = GetAttachmentResponse<FileStreamDownloadModel>(id);
response.Model.Stream = response.Response.GetResponseStream();
return response.Model;
}
public interface IDownloadModel
{
string ContentType { get; }
string Name { get; set; }
}
模型類
public class FileDownloadModel : IDownloadModel
{
public byte[] Content { get; set; }
public string Name { get; set; }
public string ContentType { get { return "application/octet-stream"; } }
}
public class FileStreamDownloadModel : IDownloadModel
{
public Stream Stream { get; set; }
public string Name { get; set; }
public string ContentType { get { return "application/octet-stream"; } }
}
Bueller? Bueller?我所得到的就是這個蟋蟀。 – tvanfosson
如果兩個應用程序都在您的控制之下,您可以允許來自其他域的跨站點腳本,並使用Javascript顯示您喜歡的任何附件。請參閱:HttpContext.Current.Response.AddHeader(「Access-Control-Allow-Origin」,「」); –
wilsotc