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

允我心安 提交于 2019-11-28 02:24:52

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

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

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" };
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!