簡體   English   中英

如何返回自定義 http 狀態碼 CoreWCF?

[英]How to return custom http status code CoreWCF?

我正在接管遺留 SOAP 項目,我需要用 .NET 核心解決方案替換 SOAP 服務。 我們不能更改 SOAP 客戶端,因此我們不能查看 REST、GRPC 等。我查看了 SoapCore 和 CoreWCF,並且都使用 SOAP header 用戶名/密碼驗證演示,但是,我將使用 CoreWCF暫時。

現有SOAP服務使用自定義http狀態碼響應,例如服務處理后返回202,在某些情況下會出現SOAP Fault。 我意識到這是不正確的,但是,我們需要維護現有的業務邏輯。

我的問題是:

  1. 如何將我的服務配置為在服務完成后或滿足特定條件時以 http 狀態代碼 202 響應? IsOneWay=True OperationContract 將不起作用,因為它會立即返回。
  2. 我將如何配置 SOAP Fault 以使用自定義 http 狀態代碼進行響應?

有許多舊的 SO 帖子提到 WebOperationContext,但是,我似乎無法在我的服務中訪問它。 OperationContext 似乎無法控制 HttpStatusCode。 也許我錯過了什么。 IE:

WebOperationContext ctx = WebOperationContext.Current;
ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.BadRequest;

這是我的示例項目細分:

程序.cs

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using System.Diagnostics;

namespace CoreWcf.Samples.Http
{
    public class Program
    {
        public const int HTTP_PORT = 8088;
        public const int HTTPS_PORT = 8443;

        static void Main(string[] args)
        {
            IWebHost host = CreateWebHostBuilder(args).Build();
            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
           WebHost.CreateDefaultBuilder(args)
            .UseKestrel(options =>
            {
                options.ListenLocalhost(HTTP_PORT);
                options.ListenLocalhost(HTTPS_PORT, listenOptions =>
                {
                    listenOptions.UseHttps();
                    if (Debugger.IsAttached)
                    {
                        listenOptions.UseConnectionLogging();
                    }
                });
            })
            .UseStartup<BasicHttpBindingStartup>();
    }
}

啟動.cs

using CoreWCF;
using CoreWCF.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace CoreWcf.Samples.Http
{
    public class BasicHttpBindingStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            //Enable CoreWCF Services, with metadata (WSDL) support
            services.AddServiceModelServices()
                .AddServiceModelMetadata();
        }

        public void Configure(IApplicationBuilder app)
        {
            var wsHttpBindingWithCredential = new BasicHttpBinding(CoreWCF.Channels.BasicHttpSecurityMode.TransportWithMessageCredential);
            wsHttpBindingWithCredential.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;

            app.UseServiceModel(builder =>
            {
                // Add the Demo Service
                builder.AddService<DemoService>(serviceOptions =>
                {
                    // Set a base address for all bindings to the service, and WSDL discovery
                    serviceOptions.BaseAddresses.Add(new Uri($"http://localhost:{Program.HTTP_PORT}/DemoService"));
                    serviceOptions.BaseAddresses.Add(new Uri($"https://localhost:{Program.HTTPS_PORT}/DemoService"));
                })
                // Add BasicHttpBinding endpoint
                .AddServiceEndpoint<DemoService, IDemo>(wsHttpBindingWithCredential, "/wsHttpUserPassword", ep => { ep.Name = "AuthenticatedDemoEP"; });

                builder.ConfigureServiceHostBase<DemoService>(CustomUserNamePasswordValidator.AddToHost);

                // Configure WSDL to be available over http & https
                var serviceMetadataBehavior = app.ApplicationServices.GetRequiredService<CoreWCF.Description.ServiceMetadataBehavior>();
                serviceMetadataBehavior.HttpGetEnabled = serviceMetadataBehavior.HttpsGetEnabled = true;
            });
        }
    }
}

IDemo.cs(服務接口):

using CoreWCF;

namespace CoreWcf.Samples.Http
{
    // Define a service contract.
    [ServiceContract]
    public interface IDemo
    {
        //[OperationContract(IsOneWay = true)]
        [OperationContract]
        string DemoRequest(string tagid, string readerid, string datetime);
    }
}

Demo.cs(服務):

using CoreWCF.Channels;
using Microsoft.AspNetCore.Http;
using System.Net;


namespace CoreWcf.Samples.Http
{
    public class DemoService : IDemo
    {
        public string DemoRequest(string tagid, string readerid, string datetime)
        {
            
            return $"Received tagid: {tagid}; readerid: {readerid};  datetime: {datetime}";
        }
    }
}

自定義用戶名密碼驗證器.cs:

using CoreWCF;
using System.Threading.Tasks;

namespace CoreWcf.Samples.Http
{
    internal class CustomUserNamePasswordValidator : CoreWCF.IdentityModel.Selectors.UserNamePasswordValidator
    {
        public override ValueTask ValidateAsync(string userName, string password)
        {
            bool valid = userName.ToLowerInvariant().EndsWith("valid")
                && password.ToLowerInvariant().EndsWith("valid");
            if (!valid)
            {
                throw new FaultException("Unknown Username or Incorrect Password");
            }
            return new ValueTask();
        }

        public static void AddToHost(ServiceHostBase host)
        {
            var srvCredentials = new CoreWCF.Description.ServiceCredentials();
            srvCredentials.UserNameAuthentication.UserNamePasswordValidationMode = CoreWCF.Security.UserNamePasswordValidationMode.Custom;
            srvCredentials.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNamePasswordValidator();
            host.Description.Behaviors.Add(srvCredentials);
        }
    }

}

非常感謝您提供的任何幫助。 干杯。

OutgoingResponse StatusCode 是您設置響應代碼的地方,但它不是 integer 值。

如果還想用,試試ASP.NET兼容模式。 部署必須在 IIS。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM