【问题标题】:How to pass endpoint details dynamically from configuration?如何从配置中动态传递端点详细信息?
【发布时间】:2017-05-09 16:33:28
【问题描述】:

我跟随 article 将 WCF 服务包含到我的 ASP.NET 核心应用程序中。

查看reference.cs 中的下面一行,默认端点配置似乎是在reference.cs 中硬编码的。

return new System.ServiceModel.EndpointAddress("http://localhost:49945/SimpleService.svc");

这就是我在 asp.net 核心控制器中创建客户端的方式-

BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
            EndpointAddress endpointAddress = new EndpointAddress("http://localhost:49945/SimpleService.svc");
            wcfClient = new SimpleServiceClient(basicHttpBinding, endpointAddress);

所以我的问题是-

  1. 我应该在哪里维护端点详细信息,以便在部署期间可以轻松配置?

  2. 如何从配置文件 (appsetting.json) 动态传递端点详细信息(地址和绑定)

生成的 Reference.cs 文件如下所示-

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     //
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace SimpleServiceReference
{
    using System.Runtime.Serialization;


    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "0.5.0.0")]
    [System.Runtime.Serialization.DataContractAttribute(Name="CompositeType", Namespace="http://schemas.datacontract.org/2004/07/SimpleService")]
    public partial class CompositeType : object
    {

        private bool BoolValueField;

        private string StringValueField;

        [System.Runtime.Serialization.DataMemberAttribute()]
        public bool BoolValue
        {
            get
            {
                return this.BoolValueField;
            }
            set
            {
                this.BoolValueField = value;
            }
        }

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string StringValue
        {
            get
            {
                return this.StringValueField;
            }
            set
            {
                this.StringValueField = value;
            }
        }
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "0.5.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="SimpleServiceReference.ISimpleService")]
    public interface ISimpleService
    {

        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISimpleService/GetData", ReplyAction="http://tempuri.org/ISimpleService/GetDataResponse")]
        System.Threading.Tasks.Task<string> GetDataAsync(int value);

        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/ISimpleService/GetDataUsingDataContract", ReplyAction="http://tempuri.org/ISimpleService/GetDataUsingDataContractResponse")]
        System.Threading.Tasks.Task<SimpleServiceReference.CompositeType> GetDataUsingDataContractAsync(SimpleServiceReference.CompositeType composite);
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "0.5.0.0")]
    public interface ISimpleServiceChannel : SimpleServiceReference.ISimpleService, System.ServiceModel.IClientChannel
    {
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("dotnet-svcutil", "0.5.0.0")]
    public partial class SimpleServiceClient : System.ServiceModel.ClientBase<SimpleServiceReference.ISimpleService>, SimpleServiceReference.ISimpleService
    {

    /// <summary>
    /// Implement this partial method to configure the service endpoint.
    /// </summary>
    /// <param name="serviceEndpoint">The endpoint to configure</param>
    /// <param name="clientCredentials">The client credentials</param>
    static partial void ConfigureEndpoint(System.ServiceModel.Description.ServiceEndpoint serviceEndpoint, System.ServiceModel.Description.ClientCredentials clientCredentials);

        public SimpleServiceClient() : 
                base(SimpleServiceClient.GetDefaultBinding(), SimpleServiceClient.GetDefaultEndpointAddress())
        {
            this.Endpoint.Name = EndpointConfiguration.BasicHttpBinding_ISimpleService.ToString();
            ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
        }

        public SimpleServiceClient(EndpointConfiguration endpointConfiguration) : 
                base(SimpleServiceClient.GetBindingForEndpoint(endpointConfiguration), SimpleServiceClient.GetEndpointAddress(endpointConfiguration))
        {
            this.Endpoint.Name = endpointConfiguration.ToString();
            ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
        }

        public SimpleServiceClient(EndpointConfiguration endpointConfiguration, string remoteAddress) : 
                base(SimpleServiceClient.GetBindingForEndpoint(endpointConfiguration), new System.ServiceModel.EndpointAddress(remoteAddress))
        {
            this.Endpoint.Name = endpointConfiguration.ToString();
            ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
        }

        public SimpleServiceClient(EndpointConfiguration endpointConfiguration, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(SimpleServiceClient.GetBindingForEndpoint(endpointConfiguration), remoteAddress)
        {
            this.Endpoint.Name = endpointConfiguration.ToString();
            ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
        }

        public SimpleServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress)
        {
        }

        public System.Threading.Tasks.Task<string> GetDataAsync(int value)
        {
            return base.Channel.GetDataAsync(value);
        }

        public System.Threading.Tasks.Task<SimpleServiceReference.CompositeType> GetDataUsingDataContractAsync(SimpleServiceReference.CompositeType composite)
        {
            return base.Channel.GetDataUsingDataContractAsync(composite);
        }

        public virtual System.Threading.Tasks.Task OpenAsync()
        {
            return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginOpen(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndOpen));
        }

        public virtual System.Threading.Tasks.Task CloseAsync()
        {
            return System.Threading.Tasks.Task.Factory.FromAsync(((System.ServiceModel.ICommunicationObject)(this)).BeginClose(null, null), new System.Action<System.IAsyncResult>(((System.ServiceModel.ICommunicationObject)(this)).EndClose));
        }

        private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
        {
            if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ISimpleService))
            {
                System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
                result.MaxBufferSize = int.MaxValue;
                result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
                result.MaxReceivedMessageSize = int.MaxValue;
                result.AllowCookies = true;
                return result;
            }
            throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
        }

        private static System.ServiceModel.EndpointAddress GetEndpointAddress(EndpointConfiguration endpointConfiguration)
        {
            if ((endpointConfiguration == EndpointConfiguration.BasicHttpBinding_ISimpleService))
            {
                return new System.ServiceModel.EndpointAddress("http://localhost:49945/SimpleService.svc");
            }
            throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
        }

        private static System.ServiceModel.Channels.Binding GetDefaultBinding()
        {
            return SimpleServiceClient.GetBindingForEndpoint(EndpointConfiguration.BasicHttpBinding_ISimpleService);
        }

        private static System.ServiceModel.EndpointAddress GetDefaultEndpointAddress()
        {
            return SimpleServiceClient.GetEndpointAddress(EndpointConfiguration.BasicHttpBinding_ISimpleService);
        }

        public enum EndpointConfiguration
        {

            BasicHttpBinding_ISimpleService,
        }
    }
}

【问题讨论】:

    标签: wcf asp.net-core


    【解决方案1】:

    我过去也需要同样的东西,并最终将 WCF 服务的连接详细信息存储在应用程序的选项中。我将详细信息存储在 appsettings.json 文件中,创建了一个 Options 类,并将其注册到服务设置逻辑中,以便在创建 WCF 服务时请求它。

    只写我的代码,我只是快速完成了这个。我还没有测试过常见的错误,比如缺少大括号、分号或拼写错误:-P

    选项类

    public class MyServiceOptions
    {
        public string EndpointUrl {get;set;}
    }
    

    摘自 startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<MyServiceOptions>Configuration.GetSection("MyService"));
        //Other calls as needed...
    
    }
    

    appsettings.json

    {
        "MyService": {
            "EndpointUrl": "http://localhost:49945/SimpleService.svc"
        }
    }
    

    然后您可以通过多种方式从依赖注入容器请求IOptions&lt;MyServiceOptions&gt; 的实例来访问您的选项。

    public class MyController : Controller
    {
        //Option 1, in controller constructor
        private IOptions<MyServiceOptions> myOptions;
    
        public MyController(IOptions<MyServiceOptions> myOptions1)
        {
            myOptions = myOptions1
        }
    
        //Option 2, in action method signature
        public IActionResult MyAction([FromServices]IOptions<MyServiceOptions> myOptions2)
        {
            //Option 3, directly
            var myOptions3 = HttpContext.RequestServices.GetService<IControllerFactory>();
            //NOTE: The GetService<>() method is an extension method from the Microsoft.Extensions.DependencyInjection namespace
    
    
            BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
            EndpointAddress endpointAddress = new EndpointAddress(myOptions.Value.EndpointUrl);
            wcfClient = new SimpleServiceClient(basicHttpBinding, endpointAddress);
        }
    }
    

    【讨论】:

    • 谢谢,这将解决地址部分。但是绑定部分仍然是硬编码的,对吗?早些时候,我们曾经有这个配置 - &lt;endpoint address="http://localhost:49945/SimpleService" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_ISimpleService" contract="ServiceReference1.ISimpleService" name="BasicHttpBinding_ISimpleService"&gt; 在部署期间更容易修改。
    • 过去是通过 asp.net 配置文件完成的,而 MVC Core(和 .NET Core)不再使用。相反,配置详细信息应该在 AppSettings 中。如果您需要备用绑定(http、与 https、其他传输设置等),您可能必须通过在 Options 类上放置标志/设置并在代码中手动处理它们来手动处理此问题。如果有一种方法可以在 ASP.NET Core 中定义 WCF 绑定的配置并让它自动为您连接所有内容,我不知道。
    • 感谢尼克的反馈
    猜你喜欢
    • 1970-01-01
    • 2017-07-26
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 2016-11-24
    • 1970-01-01
    • 2013-05-29
    相关资源
    最近更新 更多