【发布时间】:2014-09-23 18:10:01
【问题描述】:
更新 (8/7/2014) - 这个问题的解决方案是我需要添加一个派生自“UserNamePasswordValidator”的类并将其注册到 Web.Config。
我创建了一个简单的测试 WCF 服务和测试控制台客户端应用程序(代码见下文)。我正在使用 .NET 4.5.1。我已经在 StackOverflow 上搜索过重复的内容(找到了类似的帖子 here 和 here)——但是我觉得引用的帖子可能已经过时了,而且我觉得我的帖子范围更有限。
现在看例子:
解决方案当前使用会话(在 ITestService.cs 中):
[ServiceContract(SessionMode = SessionMode.Required)]
...并使用 wsHttpBinding(见下文 app.config 和 web.config)。
当我将它部署到服务器时,我可以通过使用 HTTPS 的 Web 浏览器成功访问它,如下所示:https://myserver.com/test/testservice.svc
但是,当我在客户端 app.config 中更改端点时:
http://localhost:20616/TestService.svc/TestService.svc
到:
https://myserver.com/test/testservice.svc
然后再次运行控制台应用程序,我收到错误:“提供的 URI 方案 'https' 无效;应为 'http'。参数名称:via”
我的问题是,在不更改 SessionMode.Required 的情况下,我需要做的最小更改是多少?
这是客户端控制台应用程序代码。请务必将“mycomputer\Matt”的 App.Config 值更改为适合您机器的正确值。
Program.cs
using System;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
Console.Clear();
Console.WriteLine("Attempting to log in...");
try
{
TestServiceReference.TestServiceClient client = new TestServiceReference.TestServiceClient();
bool loginSuccess = client.LogIn("admin", "password");
if (loginSuccess)
{
Console.WriteLine("Successfully logged in.");
string secretMessage = client.GetSecretData();
Console.WriteLine("Retrieved secret message: " + secretMessage);
}
else
{
Console.WriteLine("Log in failed!");
}
}
catch (Exception exc)
{
Console.WriteLine("Exception occurred: " + exc.Message);
}
Console.WriteLine("Press ENTER to quit.");
Console.ReadLine();
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ITestService"/>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://myserver.com/test/testservice.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITestService" contract="TestServiceReference.ITestService" name="WSHttpBinding_ITestService">
<identity>
<userPrincipalName value="mycomputer\Matt"/>
</identity>
</endpoint>
<!--<endpoint address="http://localhost:20616/TestService.svc/TestService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ITestService" contract="TestServiceReference.ITestService" name="WSHttpBinding_ITestService">
<identity>
<userPrincipalName value="mycomputer\Matt"/>
</identity>
</endpoint>-->
</client>
</system.serviceModel>
</configuration>
WCF 服务代码。
ITestService.cs:
using System.ServiceModel;
namespace WcfSessionsOverHttpsTest
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ITestService
{
[OperationContract(IsInitiating = true)]
bool LogIn(string username, string password);
[OperationContract(IsInitiating = false, IsTerminating = true)]
bool LogOut();
[OperationContract(IsInitiating = false)]
string GetSecretData();
}
}
TestService.svc:
namespace WcfSessionsOverHttpsTest
{
public class TestService : ITestService
{
public bool IsAuthenticated { get; set; }
bool ITestService.LogIn(string username, string password)
{
if (username == "admin" && password == "password")
{
IsAuthenticated = true;
return true;
}
else
{
IsAuthenticated = false;
return false;
}
}
bool ITestService.LogOut()
{
IsAuthenticated = false;
return true;
}
string ITestService.GetSecretData()
{
if (!IsAuthenticated)
{
throw new System.Security.Authentication.AuthenticationException("User has not logged in.");
}
else
{
string secretMessage = "The Red Sox are going to win the World Series in 2016";
return secretMessage;
}
}
}
}
Web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.1"/>
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="WcfSessionsOverHttpsTest.TestService">
<endpoint address="/TestService.svc" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="WcfSessionsOverHttpsTest.ITestService"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme="http"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
提前感谢您的帮助!
马特
【问题讨论】:
-
至少要启用 HTTPS/SSL,您的绑定中至少需要
<security mode="Transport">。 -
我将
添加到客户端和服务绑定中。现在我在客户端收到以下异常消息:“Contract 需要 Session,但 Binding 'WSHttpBinding' 不支持它或未正确配置以支持它。” -
添加:
到客户端和服务绑定导致在myserver.com/test/testservice.svc没有端点监听可以接受消息。这通常是由不正确的地址或 SOAP 操作引起的。有关更多详细信息,请参阅 InnerException(如果存在)。内部异常消息:远程服务器返回错误:(404)未找到。 -
"远程服务器返回错误:(404) Not Found。"显然是一个误导性的错误。 myserver.com/test/testservice.svc 仍然可以在浏览器中使用(注意:域显然不是 myserver.com,但我用它来隐藏我的实际域)。谢谢你。有什么想法吗?
-
我对您的确切(所需)配置没有具体经验。我的建议是启用 WCF 跟踪并查看生成的日志。它们通常具有比异常消息更详细的诊断信息。
标签: c# wcf https wcf-binding