我对GeckoFX文件的下载有一些问题。
我尝试了在一些位置描述的LauncherDialog方法,比如How to handle downloading in GeckoFX 29,以及WebRequest / Webclient方法。
这两种方法都可以工作,但它们对服务器执行两次请求。第一个将触发LauncherDialog.Download事件,LauncherDialog将发出一个新请求以获取实际文件。
我在客户端的自定义web客户机中使用GeckoFX,在这种情况下,这个下载请求需要服务器端几秒钟的处理,并修改数据状态。第二个请求被延迟,返回的数据与第一个请求的数据不一样。
而且,这个特定的应用程序不需要任何类型的下载进度窗口。
是否有任何方法从初始请求中获取数据流?修改不是问题。我更希望避免对GeckoFX进行任何修改,但如果需要,我会这样做的。
发布于 2017-06-03 18:40:07
嗯,我重新审视了我对XPCOM编程的错误假设,查看了Firefox/Gecko源代码中选定的位置,并找到了一个解决方案。对于具有XPCOM/XUL编程经验的人来说,这可能是非常明显的,但最初并不适合我。所以我想分享我的解决方案可以帮助一些人。
在我的例子中,LauncherDialog方法绝对不是要走的路。
相反,我实现了nsIFactory、nsIExternalHelperAppService和nsIStreamListener接口。
nsiStreamListener
internal class MyStreamListener : nsIStreamListener
{
public MyStreamListener(/*...*/) { }
public void OnStartRequest(nsIRequest aRequest, nsISupports aContext)
{
// This will get called once, when the download "begins".
// You can initialize your things here.
}
public void OnStopRequest(nsIRequest aRequest, nsISupports aContext, int aStatusCode)
{
// This will also get called once, when the download is
// complete or interrupted. You can perform the post-download
// actions here.
if (aStatusCode != GeckoError.NS_OK) {
// download interrupted
}
else {
// download completed
}
}
public void OnDataAvailable(nsIRequest aRequest, nsISupports aContext, nsIInputStream aInputStream, ulong aOffset, uint aCount)
{
// This gets called several times with small chunks of data.
// Do what you need with the stream. In my case, I read it
// in a small buffer, which then gets written to an output
// filestream (not shown).
// The aOffset parameter is the sum of all previously received data.
var lInput = InputStream.Create(aInputStream);
byte[] lBuffer = new byte[aCount];
lInput.Read(lBuffer, 0, (int)aCount);
}
}nsIExternalHelperAppService
public class MyExternalHelperAppService : nsIExternalHelperAppService
{
public MyExternalHelperAppService(/* ... */)
{
/* ... */
}
public nsIStreamListener DoContent(nsACStringBase aMimeContentType, nsIRequest aRequest, nsIInterfaceRequestor aWindowContext, bool aForceSave)
{
var request = Request.CreateRequest(aRequest);
var lChannel = request as HttpChannel;
try {
if (lChannel != null) {
var uri = lChannel.OriginalUri;
var contentType = lChannel.ContentType;
var contentLength = lChannel.ContentLength;
var dispositionFilename = lChannel.ContentDispositionFilename;
// Do your contenttype validation, keeping only what you need.
// Make sure you clean dispositionFilename before using it.
// If you don't want to do anything with that file, you can return null;
return new MyStreamListener(/* ... */);
}
}
catch (COMException) {
/* ... */
}
return null;
}
}nsIFactory (您还可以重载GenericOneClassNsFactory):
public IntPtr CreateInstance(nsISupports aOuter, ref Guid iid)
{
// This is called when the content dispatcher gets a DISPOSITION_ATTACHMENT
// on the channel, or when it doesn't have any builtin handler
// for the content type. It needs an external helper to handle
// the content, so it creates one and calls DoContent on it.
MyExternalHelperAppService _myExternalHelperAppService = new MyExternalHelperAppService(...);
IntPtr result;
IntPtr iUnknownForObject = Marshal.GetIUnknownForObject(_myExternalHelperAppService);
Marshal.QueryInterface(iUnknownForObject, ref iid, out result);
Marshal.Release(iUnknownForObject);
return result;
}
public void LockFactory(bool @lock) {
// do nothing here, it's not used, only kept for backwards compatibility.
}然后,在初始化代码的某个地方,我用适当的契约注册了我的nsIFactory:
Xpcom.RegisterFactory(typeof(MyExternalHelperAppService).GUID,
"MyExternalHelperAppService",
"@mozilla.org/uriloader/external-helper-app-service;1",
new MyNsFactory());仅此而已。
https://stackoverflow.com/questions/44337489
复制相似问题