Googleドライブ/ドロップボックス/ ftpなどのさまざまなリポジトリからDLLをインポートして、Windowsサービス内にDLLを展開しようとしています...
しかし、新しい DLL をインスタンス化する前に、以前に実行していたインスタンスをシャットダウンする必要があります。
これにはタスクとリフレクションを使用しています。
実行時に DLL をインスタンス化するタスクをキャンセルする方法がわかりません(インスタンス化された dll は長時間実行されるアプリケーション サンプル ファイル ウォッチャーであるため..)
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
// instantiate the dll though reflection
t = Task.Factory.StartNew(() =>
{
try
{
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + @"\" + dllName);
Type type = assembly.GetType("myclass.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
}
catch (Exception ex)
{
log.Error(ex.ToString());
}
}, cts.Token);
質問: アプリケーションが新しい dll を検出し、このタスク コードを使用してそれを実行しようとする前に、タスク t をキャンセルしたいです。
EDIT キャンセルトークンコードが壊れていたので削除しました。キャンセル トークンを含む実際のコードを次に示します。
CancellationTokenSource cts = new CancellationTokenSource();
CancellationToken ct = cts.Token;
if (t != null)
{
cts.Cancel();
try
{
ct.ThrowIfCancellationRequested();
}
catch (Exception ex)
{
cts.Dispose();
t.Dispose();
}
}
// instantiate the dll though reflection
t = Task.Factory.StartNew(() =>
{
try
{
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + @"\" + dllName);
Type type = assembly.GetType("myclass.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
}
catch (Exception ex)
{
log.Error(ex.ToString());
}
}, cts.Token);
私の考えは、インスタンス化コンテキストを保持していたタスクを何らかの方法でキャンセルして破棄できれば、アセンブリが解放され、アセンブリを更新して、タスクを介して再度インスタンス化できるようになるというものでした。
私はどこかで間違っていることを知っています。親切に説明してください。
編集
私は assemblyDomain.DoCallBack(delegate) に大きな期待を寄せていました。しかし、エラーが発生します。これは、バグをスローするコードのトーンダウン バージョンです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Reflection;
namespace AppDomain
{
[Serializable]
class Program
{
static System.AppDomain assemblyDomain = null;
static void Main(string[] args)
{
var inp = "go";
while (inp.ToString().ToLower().Trim() != "stop")
{
start();
inp = Console.ReadLine();
}
}
private static void start()
{
//Check if appdomain and assembly is already loaded
if (assemblyDomain != null)
{
//unload appDomain and hence the assembly
System.AppDomain.Unload(assemblyDomain);
//Code to download new dll
}
string cwd = System.AppDomain.CurrentDomain.BaseDirectory;
string sourceFileName = @"C:\Users\guest\Documents\visual studio 2010\Projects\DotNetTraining\Lecture 1 - dotNetProgramExecution\bin\Debug\Lecture 1 - dotNetProgramExecution.exe";
string dllName = "Lecture 1 - dotNetProgramExecution.exe";
// copy the file
if (File.Exists(cwd + dllName))
{
File.Delete(cwd + dllName);
}
File.Copy(sourceFileName, cwd + dllName);
assemblyDomain = System.AppDomain.CreateDomain("assembly1Domain", null);
assemblyDomain.DoCallBack(() =>
{
var t = Task.Factory.StartNew(() =>
{
try
{
string sss = "";
Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + @"\" + dllName);
Type type = assembly.GetType("Lecture_1___dotNetProgramExecution.Program");
MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance);
minfo.Invoke(Activator.CreateInstance(type), null);
// //var pathToDll = @"assembly path";
// //var dllName = "assembly name";
// var assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + @"\" + dllName);
// var targetAssembly = assembly.CreateInstance("Lecture_1___dotNetProgramExecution.Program");
// Type type = targetAssembly.GetType();
// MethodInfo minfo = type.GetMethod("Main", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
// minfo.Invoke(targetAssembly, null);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
});
});
}
}
}
エラー :
アセンブリ 'AppDomain、Version=1.0.0.0、Culture=neutral、PublicKeyToken=null' の 'AppDomain.Program+<>c__DisplayClass2' と入力すると、シリアル化可能としてマークされていません。
スタックトレース :
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at AppDomain.Program.start() in c:\users\guest\documents\visual studio 2010\Projects\DotNetTraining\AppDomain\Program.cs:line 58
at AppDomain.Program.Main(String[] args) in c:\users\guest\documents\visual studio 2010\Projects\DotNetTraining\AppDomain\Program.cs:line 24
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
注意してください:私はシリアライズ可能としてインポートするアセンブリのクラスProgramをマークしました
namespace Lecture_1___dotNetProgramExecution
{
[Serializable]
class Program
{
static void Main()
{
更新しました :
動的にプルされたアセンブリのコード
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
namespace Lecture_1___dotNetProgramExecution
{
[Serializable]
class Program
{
static void Main()
{
try
{
Task.Factory.StartNew(() =>
{
while (true)
{
StringBuilder sb = new StringBuilder();
sb.Append("log something new yippe ");
// flush every 20 seconds as you do it
File.AppendAllText(@"C:\logs.txt", sb.ToString());
sb.Clear();
Thread.Sleep(3000);
}
});
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = @"c:\watched";
//fsw.filter = ".dll";
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.BeginInit();
//throw new FileNotFoundException();
Console.ReadLine();
}
catch (Exception ex)
{
Task.Factory.StartNew(() =>
{
while (true)
{
StringBuilder sb = new StringBuilder();
sb.Append("loggind froom exception log something");
// flush every 20 seconds as you do it
File.AppendAllText(@"C:\logs.txt", sb.ToString());
sb.Clear();
Thread.Sleep(1000);
}
});
Console.ReadLine();
}
}
static void fsw_Created(object sender, FileSystemEventArgs e)
{
throw new NotImplementedException();
}
}
}