通过HTTPS向WCF自托管REST服务发出POST请求的示例

时间:2019-08-27 16:01:11

标签: c# rest wcf post https

关于SO的同一主题,这里有很多问题,但是似乎都没有一个完整的答案。我已经检查了大多数问题/答案,并进行了测试,测试和测试。因此希望这个问题能帮助我和其他挣扎的人。

问题。

如何设置可在https上运行的WCF自托管REST服务? 这就是我尝试设置服务和客户端的方式。没用!但是我觉得每一个变化都非常接近,但是没有达到目标。

那么,有人可以帮我一个完整的示例,该示例与REST端点,HTTPS上的自托管WCF和POST请求一起使用吗?我已经尝试过从各个地方弄乱一些零碎的东西,但我无法使其正常工作! 我该放弃吗?选择其他技术?

因此,一些代码:

[ServiceHost]

        Uri uri = new Uri("https://localhost:443");

        WebHttpBinding binding = new WebHttpBinding(WebHttpSecurityMode.Transport);
        binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;

        using (ServiceHost sh = new ServiceHost(typeof(Service1), uri))
        {
            ServiceEndpoint se = sh.AddServiceEndpoint(typeof(IService1), binding, "");
            //se.EndpointBehaviors.Add(new WebHttpBehavior());

            // Check to see if the service host already has a ServiceMetadataBehavior
            ServiceMetadataBehavior smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
            // If not, add one
            if (smb == null)
                smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = false; //**http**
            smb.HttpsGetEnabled = true; //**https**
            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            sh.Description.Behaviors.Add(smb);
            // Add MEX endpoint
            sh.AddServiceEndpoint(
              ServiceMetadataBehavior.MexContractName,
              MetadataExchangeBindings.CreateMexHttpsBinding(), //**https**
              "mex"
            );

            var behaviour = sh.Description.Behaviors.Find<ServiceBehaviorAttribute>();
            behaviour.InstanceContextMode = InstanceContextMode.Single;

            Console.WriteLine("service is ready....");
            sh.Open();

            Console.ReadLine();
            sh.Close();
        }

[IService]

 [ServiceContract]
public interface IService1
{
    [WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest, UriTemplate = "Datarows_IN/")]
    [OperationContract]
    bool Save(BatchOfRows batchOfRows);
}

[服务]

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class Service1 : IService1
{
    public bool Save(BatchOfRows batchOfRows)
    {
        Console.WriteLine("Entered Save");
        return true;
    }
}

[BatchOfRows]-简化

[DataContract]
public class BatchOfRows
{
    [DataMember]
    public int ID { get; set; } = -1;
    [DataMember]
    public string Data { get; set; } = "Hej";
}

这是在SO答案和Microsoft教程之后建立在SO答案之上的。 我什至不知道例子从哪里开始,其他例子从哪里结束。 我从这里开始:https://stackoverflow.com/a/57554374/619791 直到我尝试启用https之前,一切都很好,然后一切都停止了工作。

这是我尝试过的一些客户端代码。

[WebClient]

            string uri = "https://localhost:443/Datarows_IN";
            WebClient client = new WebClient();
            client.Headers["Content-type"] = "application/json";
            client.Encoding = Encoding.UTF8;
            var b = new BatchOfRows();
            var settings = new JsonSerializerSettings() { DateFormatHandling = DateFormatHandling.MicrosoftDateFormat };

            string str2 = "{\"batchOfRows\":" + JsonConvert.SerializeObject(b, settings) + "}";
            string result = client.UploadString(uri, "POST", str2);

[HttpClient]

            string str2 = "{\"batchOfRows\":" + JsonConvert.SerializeObject(b, settings) + "}";
            var contentData = new StringContent(str2, System.Text.Encoding.UTF8, "application/json");
            //string result = client.UploadString(uri, "POST", str2);
            //HttpResponseMessage response = client.PostAsJsonAsync("https://localhost:443/Datarows_IN", b).GetAwaiter().GetResult();
            HttpResponseMessage response = client.PostAsync("https://localhost:443/Datarows_IN", contentData).GetAwaiter().GetResult();
            response.EnsureSuccessStatusCode();

[ChannelFactory] ​​

            //var c = new ChannelFactory<IService1>(binding, new EndpointAddress("https://localhost:443/Datarows_IN"));
            var c = new ChannelFactory<IService1>(binding, new EndpointAddress("https://localhost:443/"));
            ((WebHttpBinding)c.Endpoint.Binding).Security.Mode = WebHttpSecurityMode.Transport;
            ((WebHttpBinding)c.Endpoint.Binding).Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            c.Endpoint.Behaviors.Add(new WebHttpBehavior());
            var aw = c.CreateChannel();

            var b = new ModuleIntegration.Client.Objects.BatchOfRows();
            aw.Save(b);

没有一个客户工作。如果我调试我的服务端点永远不会触发。 这是即时通讯收到的当前错误:

<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
    <Code>
        <Value>Sender</Value>
        <Subcode>
            <Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:ActionNotSupported</Value>
        </Subcode>
    </Code>
    <Reason>
        <Text xml:lang="sv-SE">The message with Action '' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver.  Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).</Text>
    </Reason>
</Fault>

请帮助!为什么这么难?!?

2 个答案:

答案 0 :(得分:1)

您的服务缺少WebHttpBehavior

没有它,WebInvoke属性什么也不做,并且路径"Datarows_IN"未被识别为动作。

以下是完整的(对我有用)服务主机代码:

var binding = new WebHttpBinding()
{
    Security = {
        Mode = WebHttpSecurityMode.Transport
    }
};
var baseUri = new Uri("https://localhost:443");

using (ServiceHost sh = new ServiceHost(typeof(Service1), baseUri))
{
    var metadata = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
    if (metadata == null) {
        metadata = new ServiceMetadataBehavior();
        sh.Description.Behaviors.Add(metadata);
    }
    metadata.HttpsGetEnabled = true;

    var endpoint = sh.AddServiceEndpoint(typeof(IService1), binding, "/");
    endpoint.EndpointBehaviors.Add(new WebHttpBehavior());

    Console.WriteLine("Service is ready....");
    sh.Open();

    Console.WriteLine("Service started. Press <ENTER> to close.");
    Console.ReadLine();
    sh.Close();
}

答案 1 :(得分:0)

您的代码片段似乎非常谨慎,这导致了上述错误,即,我们应该添加WebHttpBehavior。
但是,还需要注意一件事。
通常,当我们在IIS中通过HTTPS托管服务时,要求该服务提供证书以对服务器端和客户端之间的通信进行加密和签名。 因此,在使用自托管时,理论上应该绑定证书,否则服务将无法正常工作。
为什么此服务端点地址运行良好?唯一的解释是,我们已将证书绑定到某个端口(例如IIS),该网站具有https绑定并使用默认端口。
如果自定义端口未与证书关联,则应使用以下命令绑定证书。

  

Netsh http添加sslcert ipport = 0.0.0.0:端口号   certhash = 0000000000003ed9cd0c315bbb6dc1c08da5e6   appid = {00112233-4455-6677-8899-AABBCCDDEEFF}

https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
https://docs.microsoft.com/en-us/windows/win32/http/add-sslcert
默认情况下,仅当证书存储在本地计算机而不是当前用户中时才可以设置证书。我们可以使用以下命令来管理证书。

  

Certlm.msc

祝你好运。
最后,WCF并非旨在设计Restful风格的服务。我们应该考虑Asp.net WebAPI。
https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
随时让我知道是否有什么可以帮助您的。