我需要在嵌入式系统上运行.net C#应用程序(在Windows系统上开发)作为服务/守护程序,安装最少的Ubuntu(没有X,除了ssh之外没有服务器,只有相关软件)。我创建了一个包含行<{p>>的/etc/init.d
脚本
mono-service my-.net-app.exe service
这很有效。还可以选择以交互方式启动应用程序(用于调试目的)
mono my-.net-app.exe interactive
最后一个参数是.NET应用程序的一个参数,告诉它它是否作为服务运行。这大致以这种方式实施:
private static void Main(string[] args){
if(args.Any() && args[0] != null && args[0] == "service"){
ServiceBase.Run(new[] {(ServiceBase) new MyService()});
}else{
try{
Console.Write("starting app");
if(StartWork()){
Console.Write("press any key to exit");
Console.ReadKey();
}else{
Console.WriteLine("starting app failed");
}
} // end try
finally{
StopWork();
Console.WriteLine("finished app");
}
} // end else
...
} // end Main
public class MyService : ServiceBase{
static private Thread _worker;
protected override void OnStart(string[] args){
_worker = new Thread(() => Program.StartWork(asService: true)); // this asService tells StartWork to not produce console output
_worker.Start();
}
protected override void OnStop(){
Program.StopWork();
_worker.Join(1000);
}
}
此实现的目的是允许应用程序在Linux机器上发送StopWork()
时正常(即执行SIGTERM
)。
出于安全考虑,我需要能够以非root身份运行服务。我创建了一个新用户并使其成为应用程序写入其日志文件的目录的所有者,并将其添加到各个组以使其可以访问所需的设备文件。然后,root将以
启动应用程序sudo -u newuser mono-service my-.net-app.exe service
或
sudo -u newuser mono my-.net-app.exe interactive
mono
的第二个选项效果很好,但mono-service
的第一个选项没有效果(请参阅下面的错误消息)。由于它与mono
一起使用,因此我确信用户newuser
具有访问所有相关文件和设备的适当权限。我想知道mono-service
是否被认为是一个只有root的应用程序。
我还可以使用mono
选项并抑制控制台输出,如下所示:
private static void Main(string[] args){
try{
Console.Write("starting app");
if(StartWork(consoleoutput)){ // true or false depending on whether the service argument was given
Console.Write("press any key to exit");
Console.ReadKey();
}else{
Console.WriteLine("starting app failed");
}
} // end try
finally{
StopWork();
Console.WriteLine("finished app");
}
...
} // end Main
但是,当我终止服务(即将SIGTERM发送到mono
进程)时,它会立即停止.net应用程序而不允许它执行finally
块。
最后,我的问题是指某人在未以root身份启动时是否知道mono-service
失败的原因。错误消息如下所示,正如我之前提到的,当我使用mono
而不是mono-service
时,它不存在。
ERROR Program [4] [15:03:06.795 01/12/14] Error in Main!
FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
---> NHibernate.HibernateException: Could not create the driver from SAFEmine.DataStore.Database.MonoSqliteDriver, SAFEmine.DataStore, Version=1.3.0.6, Culture=neutral, PublicKeyToken=null. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> NHibernate.HibernateException: The IDbCommand and IDbConnection implementation in the assembly Mono.Data.Sqlite could not be found. Ensure that the assembly Mono.Data.Sqlite is located in the application directory or in the Global Assembly Cache. If the assembly is in the GAC, use <qualifyAssembly/> element in the application configuration file to specify the full name of the assembly.
at NHibernate.Driver.ReflectionBasedDriver..ctor (System.String providerInvariantName, System.String driverAssemblyName, System.String connectionTypeName, System.String commandTypeName) [0x00000] in <filename unknown>:0
at NHibernate.Driver.ReflectionBasedDriver..ctor (System.String driverAssemblyName, System.String connectionTypeName, System.String commandTypeName) [0x00000] in <filename unknown>:0
at SAFEmine.DataStore.Database.MonoSqliteDriver..ctor () [0x00000] in <filename unknown>:0
at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00000] in <filename unknown>:0
或者,如果我选择mono
代替mono-service
,是否有办法从.net应用程序中捕获SIGTERM
并优雅地死掉?我试过这个:https://github.com/ServiceStack/ServiceStack/wiki/Run-ServiceStack-as-a-daemon-on-Linux,但代码无法在Visual Studio上编译,说using Mono.Unix;
和using Mono.Unix.Native
行无效。我还在Windows上安装了Mono,并尝试使用Mono编译器,但它抱怨同样的事情。
答案 0 :(得分:0)
mono-service.exe
创建一个新的AppDomain
,其中ApplicationBase
是当前目录。这可能会影响装配加载。由于您看到了这样的错误,我会尝试启用MONO_LOG_LEVEL=debug MONO_LOG_MASK=asm
和/或strace -e file
,看看它们是否提供了任何提示。
另请注意,您可以将-d
切换到mono-service
,让它为您更改目录。