Trying to add a service reference results in Bad Request (400) in one project, otherwise runs fine

后端 未结 3 1450
被撕碎了的回忆
被撕碎了的回忆 2020-12-07 06:06

I\'m in a delicate situation: As the title suggests, I can\'t seem to connect to a WCF service I wrapped up in a Windows Service. I followed the tutorial http://msdn.microso

相关标签:
3条回答
  • 2020-12-07 06:32

    Cannot say what the problem is but here is some info to help you find the problem.

    When you do "Add Service Reference" there is a http get Call that goes to the service. I am assuming that it is this Call that Returns http 400. You have a mex endpoint and httpgetenabled, missing these are the normal problems.

    You can try Reading the wsdl using a browser and see if that Works.

    Reasons could be:

    • Port 8000 is blocked
    • The IIS site is on a different port
    • You are Accessing the site using the machine name and the config uses local host
    • the binding is not enabled in iis for that port
    0 讨论(0)
  • 2020-12-07 06:32

    For anyone who is encountering similar issues without detailed error, I'll describe what my problem was about. In my Visual Studio project, I used a class similar to the following:

    public class Info
    {
      public string Key { get; set; }
      public string Value { get; set; }
    
      public Info(string key, string value)
      {
        this.Key = key;
        this.Value = value;
      }
    }
    

    The difference to the other project (which worked) is that this POCO has a constructor that takes parameters, thus doesn't provide a standard constructor without any arguments. But this is needed in order for Info objects to be serialized (I hope I use that term correctly here) and deserialized. So in order to make it work, either just add a standard constructor which may just do nothing, or (perhaps better) use the following instead:

    [DataContract]
    public class Info
    {
      [DataMember]
      public string Key { get; set; }
      [DataMember]
      public string Value { get; set; }
    
      public Info(string key, string value)
      {
        this.Key = key;
        this.Value = value;
      }
    }
    

    I didn't think about the DataContract part before, because I didn't use any custom constructor and just initialized the objects like

    Info info = new Info { Key = "a", Value = "b" };
    
    0 讨论(0)
  • 2020-12-07 06:46

    For the beginning you have to find an issue, I mean you need to know what happens on server side. You need to handler all error and log them.

    Logging errors

        public class GlobalErrorHanler: IErrorHandler 
        {
            //to use log4net you have to have a proper configuration in you web/app.config
            private static readonly ILog Logger = LogManager.GetLogger(typeof (GlobalErrorHandler));
    
            public bool HandleError(Exception error)
            {
                //if you host your app on IIS you have to log using log4net for example
                Logger.Error("Error occurred on the service side", error);
    
                //Console.WriteLine(error.Message); 
                //Console.WriteLine(error.StackTrace);
    
                return false;
            }
    
            public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
            {
                //you can provide you fault exception here
            }
        }
    

    Then service behavior (inherits Attribute to add possibility to use it as an attribute on service implementation):

    public class MyErrorHandlingBehavior : Attribute, IServiceBehavior
    {
    
        public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
            return;
        }
    
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcher disp in serviceHostBase.ChannelDispatchers)
                disp.ErrorHandlers.Add(new GlobalErrorHanler());
        }
    
        public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {        }
    }
    

    And extension element to use it in your config:

    public class ErrorHandlerExtention: BehaviorExtensionElement
    {
    
        public override Type BehaviorType
        {
            get { return typeof(MyErrorHandlingBehavior); }
        }
    
        protected override object CreateBehavior()
        {
            return new MyErrorHandlingBehavior();
        }
    }
    

    Then add to config file:

    <system.serviceModel>
      <extensions>
        <behaviorExtensions>
          <!-- Extension.ErrorHandlerExtention: fully qualified class name, ArrayList: assebmly name-->
          <add name="errorHandler" type="Extension.ErrorHandlerExtention, Extensions"/>
        </behaviorExtensions>
      </extensions>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="False"/>
    
          <!-- the name of this element must be the same as in the section behaviorExtensions -->
          <errorHandler />
    
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    </system.serviceModel>
    

    This will allow you to get an error. When you have an error get back to the forum.

    Some more posts with this technique: Error 1, Error 2

    Tracing:

    To turn on tracing you have to add such lines to a config:

    <system.diagnostics>
      <trace autoflush="true" />
      <sources>
        <source name="System.ServiceModel"
                switchValue="Information, ActivityTracing"
                propagateActivity="true">
          <listeners>
            <add name="log"
                type="System.Diagnostics.XmlWriterTraceListener"
                initializeData= "C:\traces.svclog" />
          </listeners>
        </source>
      </sources>
    </system.diagnostics>
    

    Tracing tool: Trace Viewer

    0 讨论(0)
提交回复
热议问题