停止/处置/取消任务C#

时间:2015-08-01 12:36:26

标签: c# .net task-parallel-library task cancellationtokensource

我试图通过从各种存储库(如google drive / dropbox / 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);

问题:我想在我的appication检测到新的dll并尝试通过此任务代码执行该任务之前取消该任务。

修改 我删除了取消令牌代码,因为它正在破坏。这是带有取消令牌的实际代码。

    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(委托)寄予厚望。但我得到一个错误。这是抛出错误的代码的低调版本。

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());
                       }
                   });
               });
        }
    }
}

<小时/> 错误:
键入&#39; AppDomain.Program +&lt;&gt; c__DisplayClass2&#39;在assembly&#39; AppDomain,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null&#39;未标记为可序列化。

堆栈追踪:

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()

请注意:我已将程序集中的类程序标记为可序列化

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();
        }


    }
}

1 个答案:

答案 0 :(得分:4)

根据您的问题,如果有任何可用的升级,您似乎要卸载动态加载的程序集,然后重新加载最新的程序集。在这种情况下取​​消将无济于事。事实上,我没有看到你在任何地方使用取消令牌。

卸载动态加载程序集的唯一方法是在不同的应用程序域中将程序集加载,然后在不再需要程序集的情况下卸载应用程序域本身。所以你应该这样做:

  1. 创建新的应用域。保留app域的引用,稍后您将需要它来卸载域并因此卸载。
  2. 将程序集加载到新创建的应用程序域中。
  3. 根据需要从新加载的程序集创建类型的实例并执行其方法。
  4. 当新版本的dll可用时,请卸载以前创建的应用程序域。这也将自动卸载组件。
  5. 下载新装配,然后从第1步开始。
  6. 请参阅此处了解如何在其中加载/卸载应用领域和程序集:Using AppDomain in C# to dynamically load and unload dll

    编辑:以下是AppDomain.DoCallback的代码段

    using System;
    using System.IO;
    using System.Reflection;
    using System.Threading.Tasks;
    
    
    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\deepak\Documents\visual studio 2010\Projects\ConsoleApplication1\ConsoleApplication2\bin\Debug\ConsoleApplication2.exe";
    
    
            string dllName = "ConsoleApplication2.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 = "";
                        string dllName1 = "ConsoleApplication2.exe";
                        Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + @"\" + dllName1);
                        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);
                    }
                    catch (Exception ex)
                    {
    
                        Console.WriteLine(ex.ToString());
                    }
                });
            });
        }
    }
    }
    
    
    using System;
    using System.Text;
    using System.Threading;
    
    namespace Lecture_1___dotNetProgramExecution
    {
    [Serializable]
    class Program
    {
        static void Main()
        {
            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());
                Console.WriteLine(sb.ToString());
                sb.Clear();
                Thread.Sleep(3000);
            }
        }
    }
    }