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

C# 对象引用未设置为对象的实例-WCF服务和委托(在实例化委托之前托管WCF),c#,wcf,delegates,nullreferenceexception,C#,Wcf,Delegates,Nullreferenceexception,我使用委托允许我的服务获取存储在表单中的字符串。 当我运行代码时,我的服务日志声明如下: System.NullReferenceException:对象引用未设置为对象的实例。 指向diData.DIDataCompressed=GetDIData() 我尝试在DataServer=newmodeldataservice()处设置断点在我表单的构造函数中。并注意到我的WCF服务是在我的表单构造函数的代码运行之前启动的(我从任务栏中的WcfSvcHost中获得了弹出窗口,并且在WCF服务主机窗口

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

System.NullReferenceException:对象引用未设置为对象的实例。

指向
diData.DIDataCompressed=GetDIData()

我尝试在
DataServer=newmodeldataservice()处设置断点在我表单的构造函数中。并注意到我的WCF服务是在我的表单构造函数的代码运行之前启动的(我从任务栏中的WcfSvcHost中获得了弹出窗口,并且在WCF服务主机窗口中显示ModelDataService已经启动),因此委托显然没有被实例化Update:在调用my 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>

-->
谢谢你的帮助

更新

我在表单中添加了加载事件。我仍然得到同样的错误。我尝试为我的表单(启动表单的方法)在Program.cs中的Main()方法上设置断点,并且在调用Program.cs中的Main方法之前启动服务

问题是每次我的客户机调用服务时都会创建一个新的服务实例吗?我把它设置为单身,但我做得不对吗

更新2

我想我可能是无意中把我的项目变成了一个WCF服务应用程序,而不是一个WCF服务库(我可以在表单中托管它)。我的项目的bin在项目名称中包含一个.dll。我相信这意味着它确实是一个图书馆。如果我错了,请纠正我


再次感谢

我的回答基于评论中提供的附加信息。
让WCF服务访问用户界面窗口或其组件是非常罕见的,因为服务应该在服务器的后台运行,并且不得干扰用户界面(有很多程序员在调试服务时使用消息框,但在部署解决方案之前忘记删除它们。正如人们所认为的那样,这最终导致消息框阻塞服务器)。
因此,我建议采用以下方法(顺序是有意的):

  • 尝试以无UI的方式在服务中进行抓取,例如使用WebClient或类似工具获取原始HTML文档并分析其内容
  • 如果您需要让用户与WebBrowser交互,以便能够访问您要废弃的文档(例如,用于身份验证),请像现在一样使用单独的应用程序,并将结果存储在数据库中。但是,请独立于服务使用应用程序。服务只能返回存储在数据库中的数据(可能带有时间戳,以便在检索数据时通知用户,并在数据太旧时作出反应)
  • 在应用程序中自行托管WCF服务。这样,您就可以按您想要的方式组合应用程序和服务。缺点是,您只能在应用程序运行时访问该服务,但您将能够以您想要的方式控制和同步应用程序和服务的生命周期
  • 如果前两种方法都不起作用,请改变依赖关系,以便服务启动应用程序,而不是相反。WCF服务将是只运行一次并控制应用程序的中心点。如果您试图让应用程序向服务器注册,则如果用户启动应用程序,您将遇到麻烦好几次

  • 还有一件事:您提到您想使用委托来允许服务访问应用程序中的信息。如果您想让服务以这种方式与应用程序交互,委托不会这样做,因为应用程序和服务位于不同的进程中。如果确实需要,您可以使用双工WCF服务但我认为,在按照上面所述重新构建设计后,您很可能不需要从服务访问应用程序。

    您试图实现的目标是什么?使用WCF服务的原因是什么?一个服务通常独立于应用程序运行,因此可以访问多个应用程序基于这种n:1关系,我不明白为什么您希望应用程序和服务之间在启动和初始化方面有如此紧密的耦合。如果