之前同事将Remoting服务程序置于Mono下调用成功,这两天我尝试将WCF寄宿程序移植到Mono中,遇到些问题,跟大家分享下!
参考资料:
移植Windows自宿主WCF服务到Linux/Mono2.8
完成WPF及寄宿程序的编写(在这就不详细描述了),直接运行:
在IE中输入baseAddress地址,能够正常访问,使用MoMA(MoMA Download)检测该程序也顺利通过,原本以为这样直接放到Mono中运行就可以了,不料还是遇到不少麻烦。:
首先一上来就直接在linux下使用Mono(Mono Download)启动服务程序,却被告知:
我在我Window平台下尝试使用的Mono启动该程序,也得到同样的信息。
经过一番搜索和尝试,确定是Mono版本导致的问题,最初在下载页面习惯性的就下载了——Long-term Supported Version: 2.6.7 (Release Notes),其实Mono好像是从Version2.8~才开始支持.Net 4的,所以下载——Latest Stable Version: 2.10.2 (Release Notes)安装后问题解决。
虽然同事强调说那台Linux上是取的最新版本的源码编译的,但是因为只能看到编译的版本号,不知道其对应的Release版本到底是多少,我想应该也是同样的问题。
但是从IE浏览服务时又出现了问题,得到的错误信息如下:
<?xml version="1.0" encoding="utf-8" ?>
- <Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
- <Code>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:InternalServiceFault</Value>
</Code>
- <Reason>
<Text xml:lang="en-US">The server was unable to process the request due to an internal error. The server may be able to return exception details (it depends on the server settings).</Text>
</Reason>
</Fault>
光这么看也看不出个所以然来,我们通过设置IncludeExceptionDetailInFaults来查看进一步的错误信息。
可以在配置文件中添加以下信息来打开这一开关
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
也可以通过在服务类上添加熟悉标记来设置开关
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class ModelService : IModelService
{
}
再次执行之前的操作,可以的到如下信息:
<?xml version="1.0" encoding="utf-8" ?>
- <Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
- <Code>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:InternalServiceFault</Value>
</Code>
- <Reason>
<Text xml:lang="en-US">XmlSchema error: Named item http://schemas.microsoft.com/2003/10/Serialization/:anyType was already contained in the schema object table. Consider setting MONO_STRICT_MS_COMPLIANT to 'yes' to mimic MS implementation. Related schema item SourceUri: , Line 3, Position 3.</Text>
</Reason>
- <Detail>
- <ExceptionDetail xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel">
<HelpLink i:nil="true" />
<InnerException i:nil="true" />
<Message>XmlSchema error: Named item http://schemas.microsoft.com/2003/10/Serialization/:anyType was already contained in the schema object table. Consider setting MONO_STRICT_MS_COMPLIANT to 'yes' to mimic MS implementation. Related schema item SourceUri: , Line 3, Position 3.</Message>
<StackTrace>at System.Xml.Schema.ValidationHandler.RaiseValidationEvent (System.Xml.Schema.ValidationEventHandler handle, System.Exception innerException, System.String message, System.Xml.Schema.XmlSchemaObject xsobj, System.Object sender, System.String sourceUri, XmlSeverityType severity) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchemaObject.error (System.Xml.Schema.ValidationEventHandler handle, System.String message, System.Exception innerException, System.Xml.Schema.XmlSchemaObject xsobj, System.Object sender) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchemaObject.error (System.Xml.Schema.ValidationEventHandler handle, System.String message) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchemaUtil.AddToTable (System.Xml.Schema.XmlSchemaObjectTable table, System.Xml.Schema.XmlSchemaObject obj, System.Xml.XmlQualifiedName qname, System.Xml.Schema.ValidationEventHandler h) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchema.DoCompile (System.Xml.Schema.ValidationEventHandler handler, System.Collections.Hashtable handledUris, System.Xml.Schema.XmlSchemaSet col, System.Xml.XmlResolver resolver) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchema.CompileSubset (System.Xml.Schema.ValidationEventHandler handler, System.Xml.Schema.XmlSchemaSet col, System.Xml.XmlResolver resolver, System.Collections.Hashtable handledUris) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchema.CompileSubset (System.Xml.Schema.ValidationEventHandler handler, System.Xml.Schema.XmlSchemaSet col, System.Xml.XmlResolver resolver) [0x00000] in <filename unknown>:0 at System.Xml.Schema.XmlSchemaSet.Reprocess (System.Xml.Schema.XmlSchema schema) [0x00000] in <filename unknown>:0 at System.Runtime.Serialization.XsdDataContractExporter.Export (System.Type type) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.WsdlExporter.GetSchemaElementForPart (System.ServiceModel.Description.MessagePartDescription part, System.Xml.Schema.XmlSchema schema) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.WsdlExporter.ExportParameters (System.ServiceModel.Description.MessageBodyDescription msgbody, System.String name, System.String ns) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.WsdlExporter.ExportMessageBodyDescription (System.ServiceModel.Description.MessageBodyDescription msgbody, System.String name, System.String ns) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.WsdlExporter.ExportContractInternal (System.ServiceModel.Description.ContractDescription contract, Boolean rejectDuplicate) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.WsdlExporter.ExportEndpoint (System.ServiceModel.Description.ServiceEndpoint endpoint, Boolean rejectDuplicate) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.WsdlExporter.ExportEndpoints (IEnumerable`1 endpoints, System.Xml.XmlQualifiedName name) [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.ServiceMetadataExtension.get_Metadata () [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.HttpGetWsdl.GetMetadata () [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.HttpGetWsdl.EnsureMetadata () [0x00000] in <filename unknown>:0 at System.ServiceModel.Description.HttpGetWsdl.Get (System.ServiceModel.Channels.Message req) [0x00000] in <filename unknown>:0 at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (System.Reflection.MonoMethod,object,object[],System.Exception&) at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0</StackTrace>
<Type>System.Xml.Schema.XmlSchemaException</Type>
</ExceptionDetail>
</Detail>
</Fault>
我在“anyType was already contained in the schema object table. Consider setting MONO_STRICT_MS_COMPLIANT to 'yes' to mimic MS implementation. Related schema item SourceUri”这句话上纠缠了很久,试图在网上找到相应的信息,但收获不大,一直弄不明白“MONO_STRICT_MS_COMPLIANT ”是个什么东东,需要怎么处理,应该在什么地方去设置?
甚至尝试用MonoDevelop(MonoDevelop Download)来编译项目也解决不了问题(不过也好,对MonoDevelop也有了一些了解)。
随后索性死马当活马医了,因为看到XmlSchemaUtil.cs有这样一句代码:
internal static readonly bool StrictMsCompliant = Environment.GetEnvironmentVariable ("MONO_STRICT_MS_COMPLIANT") == "yes";
就尝试在自己的代码中使用类似的方法,通过判断发现得到的“MONO_STRICT_MS_COMPLIANT”的值的确不为Yes。同时发现Environment不仅有Get方法也有对应的Set方法,试着做了如下处理:
if (Environment.GetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT") == "yes")
Console.WriteLine("当前环境变量“MONO_STRICT_MS_COMPLIANT”值为Yes!");
else
Console.WriteLine("当前环境变量“MONO_STRICT_MS_COMPLIANT”值为No!");
Environment.SetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT", "yes");
Console.WriteLine("设置环境变量“MONO_STRICT_MS_COMPLIANT”为Yes!");
if (Environment.GetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT") == "yes")
Console.WriteLine("当前环境变量“MONO_STRICT_MS_COMPLIANT”值为Yes!");
else
Console.WriteLine("当前环境变量“MONO_STRICT_MS_COMPLIANT”值为No!");
最后输出如下
奇怪的是每次程序启动得到的值都为"No”,看来这种方式对该变量的改变只是一时的。
最后程序添加了这样一段代码来设置这一变量
if (Environment.GetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT") != "yes")
{
Environment.SetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT", "yes");
Console.WriteLine("设置环境变量“MONO_STRICT_MS_COMPLIANT”为Yes!");
}
现在启动服务后,再用IE访问就能得到如下信息了,Mono下访问得到的界面跟之前的不太一样,但实质都是一样的: