3

次のことを実現する WCF サービスを構築できるようにしたいと考えています。

  • JSON を RESTful に公開
  • XML を RESTful に公開
  • SOAP を公開する
  • 必要に応じてその他のバインディング

ここで重要なのは、コードで個別に指定したり、RESTful メソッドの個別の関数の上に指定したりするのではなく、必要なメソッドごとにコードで記述された 1 つの関数のみを構成で行いたいということです。私は多くの調査を行ってきましたが、これが純粋に構成によって可能であるかどうかについて、確かなものを見つけることができません。ResponseFormat=ResponseFormat.JsonResponseFormat=ResponseFormat.Xml

奇妙なことに、プロジェクトをビルドすると、URL 経由でアクセスすると RESTful メソッドが機能しますが、WSDL はエラーをスローします。

サービスのコードと構成を以下に示します。サービスはhttp://localhost/WCFでテストするためにローカルでホストされています。次の 2 つの RESTful 呼び出しは正常に機能し、ブラウザーで正常な XML と JSON を返します。

ローカルホスト/WCF/service1.svc/json/学生

ローカルホスト/WCF/service1.svc/残り/学生

しかし、 http://localhost/WCF/service1.svc?wsdlを呼び出すと、以下のエラーが発生します。webhttpBinding エンドポイント構成の 1 つを削除すると、WSDL が機能して正しく表示されるため、参照できるようになります。

ResponseFormat=ResponseFormat.JsonWSDL 生成を有効にするために、config に複数の webHttpBindings を含めることはできないのでしょうか (つまり、 などの個別のメソッドと属性を介して実行する必要があります)。または、ここで何かを間違って構成しましたか?

助けていただければ幸いです。構成を介して実行する方がはるかに簡単で、シリアライゼーションが指定された追加の機能があります。ありがとう。

WSDL 生成エラー

An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
    System.NullReferenceException: Object reference not set to an instance of an object.
       at System.ServiceModel.Description.WsdlExporter.CreateWsdlBindingAndPort(ServiceEndpoint endpoint, XmlQualifiedName wsdlServiceQName, Port& wsdlPort, Boolean& newBinding, Boolean& bindingNameWasUniquified)
       at System.ServiceModel.Description.WsdlExporter.ExportEndpoint(ServiceEndpoint endpoint, XmlQualifiedName wsdlServiceQName)
       at System.ServiceModel.Description.WsdlExporter.ExportEndpoints(IEnumerable`1 endpoints, XmlQualifiedName wsdlServiceQName)
       at System.ServiceModel.Description.ServiceMetadataBehavior.MetadataExtensionInitializer.GenerateMetadata()
       at System.ServiceModel.Description.ServiceMetadataExtension.EnsureInitialized()
       at System.ServiceModel.Description.ServiceMetadataExtension.get_Metadata()
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.InitializationData.InitializeFrom(ServiceMetadataExtension extension)
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.GetInitData()
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.TryHandleMetadataRequest(Message httpGetRequest, String[] queries, Message& replyMessage)
       at System.ServiceModel.Description.ServiceMetadataExtension.HttpGetImpl.ProcessHttpRequest(Message httpGetRequest)
       at SyncInvokeGet(Object , Object[] , Object[] )
       at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
       at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
       at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

Web.config

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="httpGetBehavior" name="WCF.Service1">
        <endpoint address="json" binding="webHttpBinding" name="jsonRest" contract="WCF.IService1" behaviorConfiguration="jsonBehavior"></endpoint>
        <endpoint address="rest" binding="webHttpBinding" name="xmlRest" contract="WCF.IService1" behaviorConfiguration="restBehaviour"></endpoint>
        <endpoint address="soap" binding="basicHttpBinding" name="soap" contract="WCF.IService1"></endpoint>
        <endpoint name="mex" address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost/WCF"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="httpGetBehavior">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp defaultOutgoingResponseFormat="Json"/>
        </behavior>
        <behavior name="restBehaviour">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>  
</configuration>

コード

public class Service1 : IService1
{       
    public IList<Student> GetStudents()
    {
        IList<Student> students = new List<Student>();
        students.Add(new Student() { FirstNme = "Bob", LastName = "Long", StudentId = 1, Subject = "Economics" });
        students.Add(new Student() { FirstNme = "Jack", LastName = "Short", StudentId = 2, Subject = "IT" });
        return students;
    }
}

[ServiceContract]
public interface IService1
{       
    [WebGet(UriTemplate = "/students")]
    [OperationContract]
    IList<Student> GetStudents();

}

[DataContract]
public class Student
{
    private int _studentId;
    private string _firstName;
    private string _lastName;
    private string _subject;

    [DataMember]
    public int StudentId
    {
        get { return _studentId; }
        set { _studentId = value; }
    }

    [DataMember]
    public string FirstNme
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    [DataMember]
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    [DataMember]
    public string Subject
    {
        get { return _subject; }
        set { _subject = value; }
    }
}
4

3 に答える 3

3

これは、1 つのサービスに json、xml、および soap エンドポイントがあると例外がスローされるという既知の問題です。

MS Connectでエラーとして報告しました。

フレームワークを 3.5 に切り替えると、それが機能するか、回避策も提供されます。リクエスト オブジェクトから content-header を取得し、コードでそれを決定して、レスポンス フォーマットを設定し、それに応じてレスポンスを返すことができます。

また、Web API では、WebGet/WebInvoke 属性に何も指定されていない場合、フレームワークはコンテンツ タイプに基づいてこれを自動的に判断し、それに応じて応答を返します。

: MS Connect でリンクを開こうとすると、MS Connect サイトでシステム エラーが発生します。回避策が必要な場合は、送信できることをお知らせください。また、MS は、1 つのサービスで 3 つの形式すべてを公開することを希望するクライアントは多くないため、修正しないことを確認しています。

于 2012-04-05T15:47:17.987 に答える
2

うーん、SOAP、JSON、および XML エンドポイントで動作する非常に単純なサービスを作成しました。そのシンプルさだけで機能しますか?

json と xml に対して個別のバインド構成 (空ではありますが) を宣言する必要があることがわかりました。構成は次のとおりです (以前は system.serviceModel セクションのみが表示されていたため、更新されています)。

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
  </system.web>

  <system.serviceModel>

    <bindings>
      <webHttpBinding>
        <!-- separate bindings are necessary -->
        <binding name="jsonBinding"/>
        <binding name="xmlBinding"/>
      </webHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>

      <endpointBehaviors>
        <behavior name="xmlEndpoint">
          <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Xml"/>
        </behavior>
        <behavior name="jsonEndpoint">
          <!-- do not specify enableWebScript or UriTemplate will not work -->
          <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Json"/>
        </behavior>
      </endpointBehaviors>
    </behaviors>

    <services>
      <service name="Services.Addressbook.AddressbookService">
        <endpoint address="" binding="basicHttpBinding" name="soap" contract="Services.Addressbook.IAddressbookService" />
        <endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange" />
        <endpoint address="json" behaviorConfiguration="jsonEndpoint" binding="webHttpBinding" bindingConfiguration="jsonBinding" name="restJson" contract="Services.Addressbook.IAddressbookService" />
        <endpoint address="xml" behaviorConfiguration="xmlEndpoint" binding="webHttpBinding" bindingConfiguration="xmlBinding" name="restXml" contract="Services.Addressbook.IAddressbookService" />
      </service>
    </services>

    <serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>

  </system.serviceModel>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

これはサービス契約です:

[ServiceContract]
public interface IAddressbookService {
  [OperationContract]
  [WebGet(UriTemplate = "Version")]
  string GetVersion();

  [OperationContract]
  [WebGet(UriTemplate = "Entries/Count")]
  int GetEntriesCount();

  [OperationContract]
  [WebGet(UriTemplate = "Entries")]
  Address[] GetEntries();

  [OperationContract]
  [WebGet(UriTemplate = "Entries/{name}")]
  Address[] SearchEntriesByName(string name);

  [OperationContract]
  [WebInvoke(Method = "POST", UriTemplate = "Entries/Add")]
  bool AddEntry(Address entry);

  [OperationContract]
  [WebInvoke(Method = "DELETE", UriTemplate = "Entries/Remove")]
  bool RemoveEntry(Address entry);
}

データ コントラクトは次のとおりです。

[DataContract]
public class Address {
  [DataMember]
  public string FirstName { get; set; }
  [DataMember]
  public string LastName { get; set; }
  [DataMember]
  public string Street { get; set; }
  [DataMember]
  public string City { get; set; }
  [DataMember]
  public int ZipCode { get; set; }
  [DataMember]
  public string Country { get; set; }
  [DataMember]
  public string Phone { get; set; }
  [DataMember]
  public string Email { get; set; }
}
于 2012-07-24T17:27:26.723 に答える
1

これを試してください

<bindings>
  <webHttpBinding>
    <binding name="webBindingXML"></binding>
    <binding name="webBindingSOAP"></binding>
  </webHttpBinding>
</bindings>
于 2012-08-30T03:15:15.980 に答える