对象引用未设置为对象的实例 - WCF服务和委托(在实例化委托之前托管的WCF)

时间:2013-12-21 04:56:34

标签: c# wcf delegates nullreferenceexception

我正在使用委托来允许我的服务获取存储在我的表单中的字符串。 当我运行代码时,我的服务日志声明如下:

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。我相信这意味着它确实是一个图书馆。如果我错了,请纠正我。

再次感谢!

1 个答案:

答案 0 :(得分:1)

我的回答是基于评论中提供的其他信息 让WCF服务访问用户界面窗口或其组件是非常罕见的,因为服务应该在服务器的后台运行,并且不得干扰用户界面(有许多程序员使用消息框的故事)在调试服务时忘记在部署解决方案之前删除它们。正如它应该的那样,这会在阻止服务器的消息框中结束。) 出于这个原因,我建议采用以下方法(顺序是按意图):

  1. 尝试以无UI方式在服务中进行抓取,例如通过使用WebClient或类似方法获取原始HTML文档并分析其内容。
  2. 如果您需要让用户与WebBrowser交互以便能够访问您要废弃的文档(例如,用于身份验证),请像现在一样使用单独的应用程序并将结果存储在数据库中。但是可以独立于服务使用该应用程序。该服务只能返回存储在数据库中的数据(可能带有时间戳,以便在检索到数据时通知用户,如果数据太旧,则可以做出反应)。
  3. 在应用程序中自托管WCF服务。通过这种方式,您可以以您想要的方式组合应用程序和服务。缺点是,只要应用程序运行,您就可以访问该服务 - 但您将能够以您希望的方式控制和同步应用程序和服务的生命周期。
  4. 如果第一种方法都不起作用,请转换依赖项,以便服务启动应用程序,而不是相反。 WCF服务将是仅运行一次并控制应用程序的中心点。如果您尝试让应用程序在服务器上注册,如果用户多次启动应用程序,则会遇到麻烦。
  5. 还有一件事:您提到要使用委托来允许服务访问应用程序中的信息。如果您希望服务以这种方式与应用程序交互,那么代理人将不会这样做,因为应用程序和服务存在于不同的进程中。如果确实需要,可以使用Duplex WCF服务。但我认为在您重新设计上述设计后,您不需要从服务访问应用程序的可能性很高。