我正在使用委托来允许我的服务获取存储在我的表单中的字符串。 当我运行代码时,我的服务日志声明如下:
System.NullReferenceException: Object reference not set to an instance of an object.
指向diData.DIDataCompressed = GetDIData();
我尝试在我的表单构造函数中的DataServer = new ModelDataService();
处设置断点。并且注意到我的WCF服务已经启动(在托盘中也是WcfSvcHost的弹出窗口,并且在我的窗体的构造函数的代码运行之前,它已经启动了ModelDataService),因此委托显然没有被实例化。 更新:在调用Program.cs中的Main()方法之前启动服务(启动表单的方法)。此外,我的解决方案唯一的启动项目是我的表格!
如何才能让我的WCF服务仅在我的表单加载时启动(所以我可以正确设置委托)?
这是我的WCF服务代码:
[ServiceBehavior(UseSynchronizationContext = false, InstanceContextMode = InstanceContextMode.Single)]
public class ModelDataService : IModelData
{
public delegate string GetData();
public GetData GetDIData { get; set; }
public ModelDataService()
{
}
public DIData GetDData()
{
DIData diData = new DIData();
diData.DIDataCompressed = GetDIData(); // **** error points here
return diData;
}
}
[DataContract]
public class DIData
{
[DataMember]
public string DIDataCompressed;
}
我应该启动服务的表单代码:
public partial class ScraperForm : Form
{
ServiceHost Host;
ModelDataService DataServer;
string DIData;
public ScraperForm()
{
InitializeComponent();
#region Start Data Server
DataServer = new ModelDataService(); // I set breakpoint here
DataServer.GetDIData = new ModelDataService.GetData(this.GetDIData);
Host = new ServiceHost(DataServer, new Uri[]
{
new Uri("http://localhost:8000")
});
Host.AddServiceEndpoint(typeof(IModelData),
new BasicHttpBinding(),
"ModelData");
Host.Open();
#endregion
DIData = "";
}
public string GetDIData()
{
return DIData; // This is updated on a timer
}
我的App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="SoccerModelService.ModelDataService">
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding"
contract="SoccerModelService.IModelData"
name ="BasicHttpBinding_IModelData">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8000/ModelData/"/>
<!--//localhost:8733/Design_Time_Addresses/ModelDataService/Service1/" /> -->
</baseAddresses>
</host>
</service>
<!--><service name="SoccerModelService.ModelDataService" behaviorConfiguration="debug">
</service> -->
</services>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxStringContentLength="8388608" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8000/ModelData/" binding="basicHttpBinding"
bindingConfiguration="BasicHttpBinding" contract="SoccerModelService.IModelData"
name="EndPoint" behaviorConfiguration="EndpointBehaviour" />
<!--<endpoint address="http://localhost:8000/ModelData" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding" name="EndPoint" behaviorConfiguration="EndpointBehaviour" /> -->
</client>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
<behavior name="debug">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="EndpointBehaviour">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
<!-- Trace-->
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning" propagateActivity="true" >
<listeners>
<add name="xml"/>
</listeners>
</source>
<source name="myUserTraceSource" switchValue="Warning, ActivityTracing">
<listeners>
<add name="xml"/>
</listeners>
</source>
</sources>
<sharedListeners>
<add name="xml"
type="System.Diagnostics.XmlWriterTraceListener"
initializeData="TraceLog.svclog" />
</sharedListeners>
<trace autoflush="true" />
</system.diagnostics>
</configuration>
感谢您的帮助!
更新
我在表单中添加了一个load事件。我仍然得到同样的错误。我尝试在我的Program.cs中的Main()方法上为我的表单(启动表单的方法)设置一个断点,并且在调试Program.cs中的main方法之前启动服务!
问题是每次我的客户端调用服务时都会创建一个新的服务实例吗?我把它设置为单身,但我做错了吗?
更新2
我认为我可能不小心让我的项目成为WCF服务应用程序,而不是WCF服务库(我可以在表单中托管)。我项目的bin包含项目名称中的.dll。我相信这意味着它确实是一个图书馆。如果我错了,请纠正我。
再次感谢!
答案 0 :(得分:1)
我的回答是基于评论中提供的其他信息 让WCF服务访问用户界面窗口或其组件是非常罕见的,因为服务应该在服务器的后台运行,并且不得干扰用户界面(有许多程序员使用消息框的故事)在调试服务时忘记在部署解决方案之前删除它们。正如它应该的那样,这会在阻止服务器的消息框中结束。) 出于这个原因,我建议采用以下方法(顺序是按意图):
还有一件事:您提到要使用委托来允许服务访问应用程序中的信息。如果您希望服务以这种方式与应用程序交互,那么代理人将不会这样做,因为应用程序和服务存在于不同的进程中。如果确实需要,可以使用Duplex WCF服务。但我认为在您重新设计上述设计后,您不需要从服务访问应用程序的可能性很高。