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

江枫思渺然 提交于 2019-11-27 04:56:54

问题


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.microsoft.com/en-us/library/ms733069%28v=vs.110%29.aspx every step and got it to work multiple times in this exact way, just not for one particular project. I really don't know what it is, I have a very simple interface with just one method as contract, my service is installed just fine and also starts just fine. Once I try to add a service reference in another project I get an error 400, Bad Request, and a metadata problem. I even rewrote the prototype project (it's basically the same project with less code in the implementation of the contract; but we're talking still below 300 lines of code) which ran perfectly fine, and came to the same error. I didn't change any of the app.config code when I did that, and I could connect before, but bad request afterwards.

What adds to the problem is that I can't post any code here (I'm working on a VM at work where I don't have internet access, plus the internet access I actually do have on the physical machine is so restricted I can't open any kind of board/forum/blog/whatever, so I can't post exact errors). Since all my minimal examples do work, my "minimal not working example" would be the total code anyway.

I'm at a total loss here. I dug through all the other topics of the bad request error and have some more checking to do tomorrow, but I thought I'd rather just post here and maybe get some advice on what/how to further test my project for errors. Just in case it helps, the app.config is the same as the following except for the service and contract names:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>    <services>
      <!-- This section is optional with the new configuration model
           introduced in .NET Framework 4. -->
      <service name="Microsoft.ServiceModel.Samples.CalculatorService"
               behaviorConfiguration="CalculatorServiceBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8000/ServiceModelSamples/service"/>
          </baseAddresses>
        </host>
        <!-- this endpoint is exposed at the base address provided by host: http://localhost:8000/ServiceModelSamples/service  -->
        <endpoint address=""
                  binding="wsHttpBinding"
                  contract="Microsoft.ServiceModel.Samples.ICalculator" />
        <!-- the mex endpoint is exposed at http://localhost:8000/ServiceModelSamples/service/mex -->
        <endpoint address="mex"
                  binding="mexHttpBinding"
                  contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="False"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

What could possibly make three attempts from scratch work, but the 4th not work again where the only difference is the size of the files and 2 added helper classes which are not doing anything else? I mean, the service has to be there, otherwise I'd get a 404 Not Found error instead, but something's wrong with the metadata although I'm using the exact(!) same app.config in another try and there it works.

Any suggestions/hints are greatly appreciated. I'll surely try increasing the buffer sizes in the binding tomorrow, I heard that helped some people, but I don't know about me there since I'm not really sending anything yet, am I? I'm just trying to add the service reference, I don't know if the size matters there. I also already tried TCP and basicHTTP bindings to the same result.

Thanks in advance and sorry for the wall of text; I got very frustrated at work today, with not even being able to research the error properly due to those stupid work conditions, and that frustration came up again writing this... ;)


回答1:


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




回答2:


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



回答3:


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" };


来源:https://stackoverflow.com/questions/23067794/trying-to-add-a-service-reference-results-in-bad-request-400-in-one-project-o

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