配置文件写法:
<services>
<service name="arManagement.arManage">
<endpoint address="net.tcp://localhost:8008/arManageService" binding="netTcpBinding"
bindingConfiguration="" contract="domain.IArManageService" />
</service>
<service name="ar.wcfhost.SystemAdmin">
<endpoint address="net.tcp://localhost:8008/SystemAdminService" binding="netTcpBinding"
bindingConfiguration="" contract="domain.ISystemAdminService" />
</service>
</services>
宿主程序写法:
var varsystemAdminHost = new ServiceHost(typeof(SystemAdmin));
systemAdminHost.Open();
var arMgtHost = new ServiceHost(typeof(ARManage));
arMgtHost.Open();
LogFactory.Log.Info("WCF 服务已开启");
其中SystemAdmin.cs为:
public class SystemAdmin : ISystemAdminService
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
接口实现为:
[ServiceContract]
public interface ISystemAdminService
{
[OperationContract]
string GetData(int value);
}
客户端访问封装:
public static IServiceFactory ServiceFactory
{
get
{
return ServiceLocator.Current.GetInstance(typeof(IServiceFactory)) as IServiceFactory;
}
}
public static void UseService<TChannel>(string uri, Action<TChannel> action) where TChannel:class
{
var channel = ServiceFactory.CreateService<TChannel>(uri);
action(channel);
try
{
((IClientChannel)channel).Close();
}
catch
{
((IClientChannel)channel).Abort();
}
}
public static void SystemAdminInvoke(Action<ISystemAdminService> action)
{
UseService(systemAdminURI,action);//const string systemAdminURI = "SystemAdminService";
}
IServiceFacotry实现:
public T CreateService<T>(string uri) where T : class
{
var binding = new NetTcpBinding();
string addressUri = $"{ConfigHelper.GetAppConfig("devServiceAddress")}{uri}";
var address = new EndpointAddress(addressUri);
var chanFactory = new ChannelFactory<T>(binding,address);
T channel = chanFactory.CreateChannel();
((IClientChannel)channel).Open();
return channel;
}
另一个问题:身份验证问题,如果调用接口需要Log日志,需要获取用户的id等信息,有必要做验证。一个经过测试可行的做法如下。
1:改造服务器端:
List<Type> hostType = new List<Type>()
{
typeof(SystemAdmin),
typeof(ARManage)
};
hosts = new List<ServiceHost>();
foreach (var item in hostType)
{
var host = new ServiceHost(item);
host.Credentials.ServiceCertificate.SetCertificate("CN=localhost", StoreLocation.LocalMachine, StoreName.My);
host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode
= System.ServiceModel.Security.UserNamePasswordValidationMode.Custom;
host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new MyManagementCallValidator();
if (host.State != CommunicationState.Opening)
host.Open();
hosts.Add(host);
}
netTcpBinding配置如下:
<netTcpBinding>
<binding name="WcfNewBinding">
<security mode="Message">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</netTcpBinding>
自定义的用户密码验证类:
public class MyManagementCallValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
}
}
客户端创建服务接口改造:
public T CreateService<T>(string uri) where T : class
{
var binding = new NetTcpBinding();
var security = new NetTcpSecurity();
security.Mode = SecurityMode.Message;
security.Transport = new TcpTransportSecurity();
security.Transport.ClientCredentialType = TcpClientCredentialType.None;
security.Message = new MessageSecurityOverTcp();
security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security = security;
string addressUri = $"{ConfigHelper.GetAppConfig("devServiceAddress")}{uri}";
var address = new EndpointAddress(new Uri(addressUri), EndpointIdentity.CreateDnsIdentity("localhost"));
var chanFactory = new ChannelFactory<T>(binding,address);
chanFactory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
UserNamePasswordClientCredential credential = chanFactory.Credentials.UserName;
credential.UserName = Global.LoginUserId;
credential.Password = Global.LoginUserPwd;
T channel = chanFactory.CreateChannel();
((IClientChannel)channel).Open();
return channel;
}
报错1:
传出消息标识检查失败。所预期的远程终结点的 DNS 标识为“xx.xx”,但是远程终结点提供的 DNS 请求为“localhost”。
解决办法:var address = new EndpointAddress(new Uri(addressUri), EndpointIdentity.CreateDnsIdentity("localhost"));
报错2:
本地开发没有问题,部署到服务器上报错:无法使用以下搜索标准找到 X.509 证书: StoreName“My”、StoreLocation“LocalMachine”、FindType“FindBySubjectDistinguishedName”、FindValue“CN=localhost”。
参考:http://www.cnblogs.com/chucklu/p/4685783.html
安装证书即可:
服务器端获取用户身份标识的写法:
IIdentity id = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity;
string userId = id.Name;
return composite;
调试程序,进入了断点:
以上为net.tcp的绑定,如果要同时支持http访问,只需增加一个http服务接口
#region 添加http访问
var httpHost = new ServiceHost(typeof(APIService));
System.ServiceModel.Channels.Binding httpbinding = new BasicHttpBinding();
httpHost.AddServiceEndpoint(typeof(IAPIService), httpbinding, "http://localhost:8002");
if (httpHost.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>() == null)
{
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
behavior.HttpGetUrl = new Uri("http://localhost:8002/api");
httpHost.Description.Behaviors.Add(behavior);
httpHost.Open();
hosts.Add(httpHost);
}
#endregion
或者:var httpHost = new ServiceHost(typeof(APIService));
httpHost.Open();
然后在配置文件中添加相应的配置:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBindingDataService">
<security mode="None">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="managgement.wcfhost.APIService" behaviorConfiguration="httpBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8002/api"/>
</baseAddresses>
</host>
<endpoint address=""
binding="basicHttpBinding" bindingConfiguration="BasicHttpBindingDataService"
contract="managgement.wcfhost.IAPIService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="httpBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>