Wcf 使用HTTPS以编程方式配置ServiceHost端点?
我使用的是无文件激活,这是服务器端的完整web.config,它有两个端点:Wcf 使用HTTPS以编程方式配置ServiceHost端点?,wcf,servicehost,Wcf,Servicehost,我使用的是无文件激活,这是服务器端的完整web.config,它有两个端点: <?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSectio
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework"
type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</configSections>
<connectionStrings>
<add name="RedStripe"
connectionString="Data Source=S964;Initial Catalog=MyDatabase;Persist Security Info=True;User ID=sa;Password=***;MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<system.web>
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<serviceHostingEnvironment>
<!-- where virtual .svc files are defined -->
<serviceActivations>
<add service="Company.Project.Business.Services.AccountClassService"
relativeAddress="Account/AccountClassService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
<add service="Company.Project.Business.Services.AccountService"
relativeAddress="Account/AccountService.svc"
factory="Company.Project.WebHost.CustomServiceHostFactory"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
这是我的CustomServiceHost:
public class CustomServiceHost : ServiceHost
{
public CustomServiceHost(Type serviceType, Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
}
protected override void InitializeRuntime()
{
AddServiceDebugBehavior();
AddWcfMessageLoggingBehavior();
AddGlobalErrorHandlingBehavior();
AddServiceCredentialBehavior();
AddEndpoints();
ConfigureThrottling();
base.InitializeRuntime();
}
private void AddEndpoints()
{
var wsHttpBinding = WcfHelpers.ConfigureWsHttpBinding();
foreach (Uri address in BaseAddresses)
{
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding, new EndpointAddress(address));
AddServiceEndpoint(endpoint);
//adding mex
AddServiceMetadataBehavior();
AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexHttpBinding(),
address.AbsoluteUri + "/mex");
break;
}
}
private void AddGlobalErrorHandlingBehavior()
{
var errorHanlderBehavior = Description.Behaviors.Find<GlobalErrorBehaviorAttribute>();
if (errorHanlderBehavior == null)
{
Description.Behaviors.Add(new GlobalErrorBehaviorAttribute(typeof(GlobalErrorHandler)));
}
}
private void AddServiceCredentialBehavior()
{
var credentialBehavior = Description.Behaviors.Find<ServiceCredentials>();
if (credentialBehavior == null)
{
var customAuthenticationBehavior = new ServiceCredentials();
customAuthenticationBehavior.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
customAuthenticationBehavior.UserNameAuthentication.CustomUserNamePasswordValidator = new CustomUserNamePasswordValidator();
Description.Behaviors.Add(customAuthenticationBehavior);
}
}
private void AddServiceDebugBehavior()
{
var debugBehavior = Description.Behaviors.Find<ServiceDebugBehavior>();
if (debugBehavior == null)
{
Description.Behaviors.Add(
new ServiceDebugBehavior() {IncludeExceptionDetailInFaults = true});
}
else
{
if (!debugBehavior.IncludeExceptionDetailInFaults)
debugBehavior.IncludeExceptionDetailInFaults = true;
}
}
private void AddServiceMetadataBehavior()
{
var metadataBehavior = Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
serviceMetadataBehavior.HttpsGetEnabled = true;
Description.Behaviors.Add(serviceMetadataBehavior);
}
}
private void AddWcfMessageLoggingBehavior()
{
var messageInspectorBehavior = Description.Behaviors.Find<WcfMessageInspector>();
if (messageInspectorBehavior == null)
{
Description.Behaviors.Add(new WcfMessageInspector());
}
}
private void ConfigureThrottling()
{
var throttleBehavior = Description.Behaviors.Find<ServiceThrottlingBehavior>();
if (throttleBehavior != null) return;
throttleBehavior = new ServiceThrottlingBehavior
{
MaxConcurrentCalls = 100,
MaxConcurrentInstances = 100,
MaxConcurrentSessions = 100
};
Description.Behaviors.Add(throttleBehavior);
}
}
当我发布此WebHost项目并尝试浏览到以下两个地址之一时:
我得到以下错误:
提供的URI方案“http”无效;应为“https”。参数
名称:context.ListenUriBaseAddress
我注意到,在CustomServiceHost AddEndpoints()方法中,当在BaseAddresss上循环时,如果我硬编码一个地址,如下所示:
然后我可以成功浏览到它。当使用无文件激活和相对寻址时,如何构建基址?我可以在哪里指定他们使用https(他们现在似乎正在使用http)
提前谢谢
编辑1:这将解决问题,但似乎是一个彻底的攻击,我在哪里使用无文件激活指定https,以便使用https生成相对地址
var endpoint = new ServiceEndpoint(ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding, new EndpointAddress(address.OriginalString.Replace("http:", "https:")));
编辑2:我想我正在了解这里发生了什么。谢谢你@Andreas K为我指明了正确的方向。如果我进入IIS并查看该站点的绑定,则有多个绑定,如图所示: 当在基地址上循环时,我在AddEndpoints()方法中放入了一些代码来写入数据库。当我尝试使用浏览器访问服务(如:)时,会在数据库中创建两个条目。 因此,似乎IIS站点绑定正在被拾取。但是,现在我不确定为什么数据库中没有更多的BaseAddresses条目。net.pipe、net.tcp等在哪里 试试这个:
WebHttpBinding binding = new WebHttpBinding();
binding.Security.Mode = WebHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None; // no password
// If you are not using IIS, you need to bind cert to port
Process proc = new Process();
proc.StartInfo.FileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.SystemX86), "netsh.exe");
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.Arguments =
string.Format("http add sslcert ipport={0}:{1} certhash={2} appid={{{3}}}", ip, port, cert.Thumbprint, Guid.NewGuid());
proc.Start();
proc.WaitForExit();
要获得证书,请执行以下操作(注意证书必须在证书存储中):
这将在没有IIS的情况下工作。如果您使用的是IIS,则无需将证书绑定到端口(我想)我在msdn上找到了以下内容: 无文件激活 尽管.svc文件使公开WCF服务变得容易,但更简单的方法是在Web.config中定义虚拟激活端点,从而完全消除对.svc文件的需要。 在WCF 4中,您可以在Web.config中定义映射到您的服务类型的虚拟服务激活端点。这使激活WCF服务成为可能,而无需维护物理.svc文件(也称为“无文件激活”)。以下示例显示如何配置激活端点:
<configuration>
<system.serviceModel>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="Greeting.svc" service="GreetingService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
实际上磁盘上没有物理的.svc文件。图9显示了它在浏览器中的外观
我希望这能帮助您事实证明,基本地址来自我的更新2中提到的IIS绑定,再次感谢@Andreas K为我指明了正确的方向。在IIS中,我有一个网站,下面有多个应用程序。我在这些绑定上同时启用了http和https。我已更新CustomServiceHost中的AddEndpoings()方法,如下所示:
private void AddEndpoints()
{
var wsHttpBinding = WcfHelpers.ConfigureWsHttpBinding();
foreach (var address in BaseAddresses.Where(a => a.Scheme == Uri.UriSchemeHttps))
{
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding,
new EndpointAddress(address));
AddServiceEndpoint(endpoint);
AddServiceMetadataBehavior();
}
}
由于站点下的其他应用程序需要http,因此我的基本地址始终包含两个(http和https)。我需要手动过滤http,因为我不想为这个特定的站点公开它们。现在我知道他们是如何居住的,我很满意。谢谢大家。你能在服务器端发布完整的app.config
吗?你是说web.config?我更新了帖子以包含完整的服务器端web.configThank,应该足够了,在哪里?我必须使用WsHttpBinding和TransportWithMessageCredential,所以不确定这是如何应用的?是的,我正在使用IIS。你能用WebHttpBinding替换你的WsHttpBinding吗?并按照我提供的示例进行配置?好的,我将我的WsHttpBinding更改为使用WebHttpBinding,重新发布到IIS,并得到相同的错误。“提供的URI方案‘http’无效;应为‘https’。”从何处获取URI?这是你的web.config吗?确保您的URI以httpst开头,这是我的问题。我正在使用无文件激活,就像在帖子中所说的那样。我只是在标签中提供相对地址。我不知道基本地址是如何填充的,也不知道如何将它们更改为使用https。是的,我已经完成了所有这些工作,并且正在发布到IIS。在我的帖子中,您将看到我有一个serviceActivations部分,其中定义了两个服务,每个服务都有一个relativeAddress、service和factory值集。我的工厂正在使用Security.Mode=TransportWithMessageCredential和Security.Message.ClientCredentialType=MessageCredentialType.Username定义wsHttpBinding。这将导致架构为https,但在我的CustomServiceHost中,基本地址始终为http。如何将它们设置为https?另外,如果尚未设置,请参阅文章中的编辑1。我可以解决这个问题,但这似乎是一个黑客行为。你在IIS上托管你的wcf服务。因此,IIS提供了到“外部”的绑定。请检查一下这个装订。是的,编辑就像一个黑客:我的PIn IIS需要检查SSL并将ClientCertificates设置为“接受”。您可以看到我在OP中使用的绑定,除非有其他我不知道的绑定?是的,IIS有自己的绑定。我认为,如果您使用WCF服务的相对地址,url只是从IIS绑定+webapp+服务一起设置的。请在IIS控制台中查看此菜单:
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
cert = store.Certificates.Find(X509FindType.FindBySubjectName, certSubject, false)[0];
<configuration>
<system.serviceModel>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="Greeting.svc" service="GreetingService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
</configuration>
private void AddEndpoints()
{
var wsHttpBinding = WcfHelpers.ConfigureWsHttpBinding();
foreach (var address in BaseAddresses.Where(a => a.Scheme == Uri.UriSchemeHttps))
{
var endpoint = new ServiceEndpoint(
ContractDescription.GetContract(Description.ServiceType),
wsHttpBinding,
new EndpointAddress(address));
AddServiceEndpoint(endpoint);
AddServiceMetadataBehavior();
}
}