简体   繁体   English

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

[英]Example of a POST request to WCF selfhosted REST service over HTTPS

There are numerus question about the same topic here on SO, but none of them seems to give a complete answer. SO上有很多关于同一主题的问题,但似乎没有一个给出完整的答案。 I have checked most of the questions/answers and tested, tested and tested.我已经检查了大部分问题/答案并进行了测试,测试和测试。 So hopefully this question will help me and others struggling.所以希望这个问题能帮助我和其他挣扎的人。

The question.问题。

How do i set up WCF selfhosted REST service that works over https?如何设置通过 https 工作的 WCF 自托管 REST 服务? This is how I have tried setting up the service and clients.这就是我尝试设置服务和客户端的方式。 It doesn't work!它不起作用! But i feel that im very close with every change, but im not reaching the goal.但我觉得我对每一个变化都非常接近,但我没有达到目标。

So, can someone help me with a complete example that is working with a REST endpoint, selfhosted WCF over HTTPS and a POST request?那么,有人可以帮助我提供一个完整的示例,该示例使用 REST 端点、通过 HTTPS 的自托管 WCF 和 POST 请求吗? I have tried puzzling together bits and pieces from everywhere and i cant get it working!我曾尝试将来自各地的点点滴滴拼凑在一起,但我无法让它发挥作用! Should i give up?我应该放弃吗? Choose another technology?选择其他技术?

So, some code:所以,一些代码:

[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);
}

[Service] [服务]

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

[BatchOfRows] - simplified [BatchOfRows] - 简化

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

This is build upon SO answer after SO answer and Microsoft tutorials.这是建立在 SO answer 和 Microsoft 教程之后的 SO answer 之上的。 I dont even know where what example started and the others ended.我什至不知道什么例子从哪里开始,其他例子在哪里结束。 I began from this: https://stackoverflow.com/a/57554374/619791 And that worked very well until i tried enabling https, then everything stopped working.我从这里开始: https : //stackoverflow.com/a/57554374/619791并且效果很好,直到我尝试启用 https,然后一切都停止工作了。

Here are some client code that i have tried.这是我尝试过的一些客户端代码。

[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] [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);

None of the clients work.没有一个客户工作。 If i debug my Service endpoint is never triggered.如果我调试我的服务端点永远不会被触发。 This is the current error that im getting:这是我得到的当前错误:

<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>

Please help!请帮忙! Why is this so hard?!?为什么这么难?!?

Your service is missing the WebHttpBehavior .您的服务缺少WebHttpBehavior

Without it, the WebInvoke attribute does nothing, and the path "Datarows_IN" is not recognized as an action.没有它, WebInvoke属性什么也不做,路径"Datarows_IN"不会被识别为一个动作。

Here's the full (works for me) service host code:这是完整的(对我有用)服务主机代码:

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();
}

Your code snippets seem very cautious, which caused the above error, and namely, we should add the WebHttpBehavior.你的代码片段看起来很谨慎,导致了上述错误,即我们应该添加WebHttpBehavior。
However, there is one more thing we should pay attention to.然而,还有一件事我们应该注意。
Ordinarily, the service is required to provide a certificate to encrypt and sign the communication between the server-side and the client-side when we hosting the service over HTTPS in IIS.通常,当我们在 IIS 中通过 HTTPS 托管服务时,该服务需要提供证书以对服务器端和客户端之间的通信进行加密和签名。 Thereby, we should bind a certificate theoretically when we use self-host, or the service should not be work properly.因此,理论上我们在使用自托管时应该绑定证书,否则服务将无法正常工作。
Why does this service endpoint address work well?为什么这个服务端点地址运行良好? The only explanation is that we have bound a certificate to the port somewhere, such as IIS, there is a website with an https binding and use the default port.唯一的解释是我们在某处绑定了证书,比如IIS,有网站绑定了https,使用默认端口。
If the custom port does not associate with a certificate we should bind a certificate by using the below command.如果自定义端口未与证书关联,我们应该使用以下命令绑定证书。

Netsh http add sslcert ipport=0.0.0.0:portnumber certhash=0000000000003ed9cd0c315bbb6dc1c08da5e6 appid={00112233-4455-6677-8899-AABBCCDDEEFF} netsh http add sslcert ipport=0.0.0.0:portnumber 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/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 https://docs.microsoft.com/en-us/windows/win32/http/add-sslcert
By default, the certificate could merely be set up when it is stored in the Local Machine instead of the Current User.默认情况下,证书只能在存储在本地计算机而不是当前用户中时进行设置。 We could manage the certificate with the below command.我们可以使用以下命令管理证书。

Certlm.msc证书文件

Wish you have good luck.祝你好运。
At last, WCF is not aimed at designing the Restful style service.最后,WCF 的目的不是设计 Restful 风格的服务。 We should consider Asp.net WebAPI.我们应该考虑 Asp.net WebAPI。
https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api https://docs.microsoft.com/en-us/aspnet/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
Feel free to let me know if there is anything I can help with.如果有什么我可以帮忙的,请随时告诉我。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM