我首先在文件夹中加载一些 dll 并将Core
类的实例与名称一起存储为 a 中的键Dictionary<string, object>
,如下所示:
const string SEARCH_PATH = "./Cores";
const string FILE_NAME_MASK = "*.core.dll";
private IProgress<double> _progress;
private Dictionary<string, object> _dlls;
public void LoadCores() {
//consts
string[] BindMethods = { "PartFinished", "DownloadFinished", "ReportError" };
//get dlls to load
IEnumerable<string> dlls = Directory.EnumerateFiles(SEARCH_PATH, FILE_NAME_MASK);
//amount of dlls
int i = 0;
Assembly assembly;
Type coreType;
object instance;
EventInfo eInfo;
MethodInfo mInfo;
Delegate del;
string asmName;
Type instanceType;
//try loading all core.dll's
foreach (string fileName in dlls) {
Debug.Write("Loading ");
Debug.WriteLine(fileName);
try {
//load assembly
assembly = Assembly.LoadFile(Path.GetFullPath(fileName));
//find core type
asmName = assembly.GetName().Name;
coreType = assembly.GetType(asmName + ".Core", true);
//create instance of core
instance = Activator.CreateInstance(coreType, _progress);
//bind core events
foreach (string t in BindMethods) {
instanceType = instance.GetType();
if (instanceType.GetMethod("Download") == null) {
throw new MissingMethodException($"The Core in '{fileName}' does not contain a Method like 'Downlaod(IEnumrable<Uri> uris, string pathTemplate)'", "Download");
}
eInfo = instanceType.GetEvent(t);
mInfo = eInfo.GetAddMethod();
try {
del = Delegate.CreateDelegate(eInfo.EventHandlerType, this, $"On{t}");
} catch (Exception ex) {
throw new ArgumentException(
$"the function '{t}' requires a Method called 'On{t}' in this scope with an '{eInfo.EventHandlerType}' compatibility",
ex);
}
mInfo.Invoke(instance, new object[] { del });
}
//dll loaded successfull
_dlls.Add(asmName.Split('.')[0], instance);
i++;
} catch (Exception ex) {
OnReportError(this, $"Error Loading {fileName}:\n{ex}");
}
}
}
更多的事件处理方法,atm 只是傻瓜:
public void OnPartFinished(object sender, KeyValuePair<int, Exception> data) {
Debug.WriteLine("Part finished: " + data.Key + "\n" + data.Value);
}
public void OnDownloadFinished(object sender, EventArgs args) {
Debug.WriteLine("Download finished.");
}
public void OnReportError(object sender, string data) {
Debug.WriteLine("Error Reported: " + data);
}
稍后,我将Download
使用其各自的参数调用该方法:
void Test(string method, IEnumerable<Uri> links, string pathTemplate) {
object instance = _dlls[method];
MethodInfo mInfo = instance.GetType().GetMethod("Download");
mInfo.Invoke(instance, new object[] { links, pathTemplate });
}
包含在 dll 中:
public class Core {
private CancellationTokenSource _cancelToken;
private readonly IProgress<double> _progress;
public event EventHandler<KeyValuePair<int, Exception>> PartFinished;
public event EventHandler DownloadFinished;
public event EventHandler<string> ReportError;
public Core(IProgress<double> progressReporter) {
_progress = progressReporter;
}
public async void Download(IEnumerable<Uri> uris, string pathTemplate) {
_cancelToken = new CancellationTokenSource();
_progress.Report(0);
int i = 1;
string p = string.Empty;
foreach (Uri uri in uris) {
try {
if (File.Exists(p = string.Format(pathTemplate, i++)))
OnPartFinished(i - 1, new IOException("File already exists"));
else {
using (Stream stream = new FileStream(p, FileMode.Create)) {
await DownloadMegaUpCore(uri, stream, _cancelToken.Token);
//DownloadMegaUpSyncronized(uri, stream, _cancelToken.Token);
}
OnPartFinished(i - 1, null);
}
} catch (OperationCanceledException ex) {
//delete semi-corrupt / unfinished files
OnReportError($"canceled on part {i - 1}");
File.Delete(p);
OnPartFinished(i - 1, ex);
break;
} catch (Exception ex) {
OnReportError($"error on part part {i - 1}:\n{ex}\n\nSkipping...");
OnPartFinished(i - 1, ex);
}
}
OnDownloadFinished();
}
private Task DownloadMegaUpCore(Uri url, Stream stream, CancellationToken token) => Task.Factory.StartNew(() => {
try {
DownloadMegaUpSyncronized(url, stream, token);
} catch (Exception ex) {
if (File.Exists("./part1.rar"))
File.Delete("./part1.rar");
}
});
到这里一切正常......
void DownloadMegaUpSyncronized(Uri url, Stream stream, CancellationToken token) {
int TextDlBlockSize = 1024 * 2;
int DataDlBlockSize = 1024 * 64;
//---------------- todo: move constants
HttpWebRequest request;
HttpWebResponse response = null;
CookieContainer cContainer = null;
cContainer = new CookieContainer(); // < here the exception accures
request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 5000;
response = (HttpWebResponse)request.GetResponse();
“奇怪”的事情是,这只发生在我尝试异步运行方法时,单线程工作得很好。
另外我已经检查过多次,我传递给任务的令牌没有被取消,除此之外,甚至在任务构造函数中都没有使用令牌。
我怀疑它与动态加载和调用 dll 有关。