1

我有一个在服务器上运行的用 C# 编写的应用程序(.NET 控制台应用程序)。有时(大约每周 2 次)应用程序崩溃,例如,这可能是由于网络出现故障或类似情况引起的,但这并不重要,但是我想要的是,当应用程序崩溃时我想要它只需默默地重新启动。我无法重写应用程序来执行此操作,因为我没有源代码,我想要一个简单的解决方案,所以我尝试创建一个像这样的 bat 文件:

:start
@BotR.TestR.exe
echo sleeping
@ping 123.45.67.89 -n 1 -w %1000 > nul
goto start

但是,每当应用程序 (BotR.TestR.exe) 崩溃时,它会弹出一个弹出窗口,告知应用程序已崩溃,并阻止它继续运行,从而阻止它重新启动。有什么简单的方法可以解决这个问题吗?

4

1 回答 1

1

我不确定这是最好的方法,但是您可以使用Mono Cecil重写应用程序来执行您想要的操作,如下所示:

ModuleDefinition module = ModuleDefinition.ReadModule(fileName);

var entryPoint = module.EntryPoint.Body;

var corlib = module.TypeSystem.Corlib;

var exceptionTypeReference = new TypeReference(
    "System", "Exception", null, corlib, false);
exceptionTypeReference = module.Import(exceptionTypeReference);

var entryPointIL = entryPoint.GetILProcessor();

var objectTypeReference = new TypeReference(
    "System", "Object", null, corlib, false);
objectTypeReference = module.Import(objectTypeReference);

var writeLineMethod =
    new MethodReference(
        "WriteLine",
        new TypeReference("System", "Void", null, corlib, true),
        new TypeReference("System", "Console", null, corlib, false))
    { Parameters = { new ParameterDefinition(objectTypeReference) } };
writeLineMethod = module.Import(writeLineMethod);

var callWriteLine = entryPointIL.Create(OpCodes.Call, writeLineMethod);
entryPointIL.Append(callWriteLine);

entryPointIL.Emit(OpCodes.Br, entryPoint.Instructions.First());

var exceptionHandler = new ExceptionHandler(ExceptionHandlerType.Catch)
                        {
                            CatchType = exceptionTypeReference,
                            TryStart = entryPoint.Instructions.First(),
                            TryEnd = callWriteLine,
                            HandlerStart = callWriteLine,
                            HandlerEnd = entryPoint.Instructions.Last()
                        };
entryPoint.ExceptionHandlers.Add(exceptionHandler);

module.Write(fileName);

这段代码所做的是获取应用程序的入口点(通常是Main()方法)并从这里重写它:

static void Main()
{
    // some code
}

进入这个:

static void Main()
{
    while (true)
    {
        try
        {
            // some code
        }
        catch (Exception exception)
        {
            Console.WriteLine(exception);
        }
    }
}

编辑:

如果Main()方法和包含类是公共的,则有一种更简单的方法:创建一个应用程序,将另一个作为引用并运行其Main(). 像这样的东西:

class Program
{
    void Main()
    {
        while (true)
        {
            try
            {
                OtherApplication.Program.Main();
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception);
            }
        }
    }
}
于 2011-11-03T14:16:36.550 回答