自托管 WCF 服务作为 Windows 服务(带自定义身份验证)






4.30/5 (5投票s)
自托管 WCF 服务作为具有自定义用户身份验证的 Windows 服务(通过 Http)。
引言
在本文中,我想演示一个非常简单的 WCF 服务器/客户端应用程序,但此演示应用程序旨在演示自托管服务。您可能会问“什么是自托管?”。让我详细解释一下。
有两种托管 WCF 服务的方法:
1. 使用 IIS 托管:托管 WCF Web 服务的传统方式。
2. 自托管:一种无需 IIS 即可托管服务的方法。
什么是自托管?
在托管应用程序中托管服务称为自托管服务。托管应用程序可以是控制台应用程序、Windows 窗体应用程序、WPF 或 Windows 服务。请查看此 MSDN 链接了解更多详情,并查看此 MSDN 链接中的示例代码。
在 asp.net 论坛上,对此自托管服务与 IIS 托管服务之间的差异进行了详细讨论。
让我们继续讨论 WCF;
WCF 有两个区域
- 服务
- 客户端
1. 服务
使服务可用的基本步骤。
- 定义服务协定
- 实现服务协定
- 托管并运行服务协定
2. 客户端
WCF 客户端是一个可以像调用方法一样与 WCF 服务操作进行通信的应用程序。
动态 WCF 客户端与服务的通信分为三个步骤:
- 使用通道工厂类(
System.ServiceModel.ChannelFactory
)创建 WCF 客户端 - 配置 WCF 客户端
- 使用 WCF 客户端
在本文中,我将使用 Windows 服务作为托管 WCF 服务的托管应用程序。
- 源代码包含Windows 服务和自托管 WCF 服务(基于 Http)。
- 所有示例均使用Visual Basic .Net 编程,
- 示例通过端口 9090(基于 Http)发送请求/响应。
- 示例使用基于INI文件的动态连接字符串,并使用简单的AES加密进行密码加密/解密。
- Https 托管的主题未包含在内。
阅读本文并研究示例后,您可能会对如何在 Windows 服务中创建具有自定义身份验证的自托管 Web 服务有所了解。
背景
最近,我有一个需求,需要托管一个带有身份验证的服务,而我没有 IIS。解决方案是使用自托管 WCF 服务,该服务使用自定义用户身份验证,并且客户端可以使用通道工厂方法动态地消耗它。
服务器端
那么,让我们从 WCF 服务开始。创建一个WCF 服务库项目,然后添加以下引用,并将项目命名为 MSMSystemService。
1. System.ServiceModel
2. System.IdentityModel
3. System.IdentityModel.Selectors
WCF 库项目
1. 向项目中添加一个接口 (IDataServices.vb),并定义服务协定。
在此示例中,我使用了来自 MSMSystemService.DataModels.Academics
的数据类。
Imports System
Imports System.ServiceModel
Imports MSMSystemService.DataModels.Academics
Namespace MSMServices
<servicecontract()>
Public Interface IDataServices
' TODO: Add your service operations here
<operationcontract()>
Function GetPupilData(ByVal lngStudentID As Long) As StudentInfo
End Interface
End Namespace
2. 添加一个数据类 (DataServices.vb) 并实现服务协定。
在此示例中,DataServices 类从 MSMSystemService.DataModels.Academics.StudentInfo
数据类返回数据。
Imports MSMSystemService.DataModels.Academics
Namespace MSMServices
Public Class DataServices
Implements IDataServices
Public Function GetPupilData(ByVal lngStudentID As Long) As StudentInfo Implements IDataServices.GetPupilData
Dim oStudent As New StudentInfo
oStudent.StudentID = lngStudentID
oStudent.Fill()
Return oStudent
End Function
End Class
End Namespace
3. 自定义身份验证
添加一个新类 (MSMServiceAuthentication.vb),并继承 System.IdentityModel.Selectors.UserNamePasswordValidator
类,并实现Validate
子程序。有一个自定义异常类(MSMSecurityException
)用于管理自定义安全令牌验证失败。
将以下代码添加到 MSMServiceAuthentication.vb。
Imports System
Imports System.Security
Imports System.Security.Principal
Imports System.IdentityModel
Imports System.IdentityModel.Selectors
Namespace MSMServices
Public Class MSMServiceAuthentication
Inherits UserNamePasswordValidator
Public Overrides Sub Validate(userName As String, password As String)
If userName = "admin" And password = "admin" Then
'OK
Else
Throw New MSMSecurityException()
End If
End Sub
End Class
Public Class MSMSecurityException
Inherits Exception
Public Sub New()
MyBase.New("Invalid Security Token")
End Sub
End Class
End Namespace
WCF 服务部分已准备就绪,下一步是创建一个托管 WCF 服务的托管应用程序。在这种情况下,Windows 服务将充当托管应用程序。
向 MSMServiceController 项目添加一个新的 Windows 服务项目(命名为MSMServiceController),并按照以下说明设置ServiceName 和Service Description 属性。
4. Windows 服务
设置服务属性
打开服务类 MSMServiceController.vb 的属性,并将“ServiceName”属性设置为“MSMDataServices”。
添加安装程序类
右键单击服务类MSMServiceController.vb 并选择“添加安装程序”。
Visual Studio 将创建一个新类ProjectInstaller.vb,其中包含两个组件:
1. ProcessInstaller (重命名为 MSMProcessInstaller)
2. Service Installer。(重命名为 MSMServiceInstaller)
打开 ProjectInstaller.vb 类并设置 Service Installer 的属性。
注意:在 Windows 服务安装后,ServiceName 和Description 属性中设置的值将在 Windows 服务管理控制台中显示。
将以下代码添加到 Windows 服务类。在此代码中,我使用了一个自定义注册表管理器和一个自定义 INI 文件管理器来从 INI 设置文件中读取连接字符串。
注意:开发人员可以使用 WSHttpBinding
类而不是 BasicHttpBinding
类来进行Https 托管(通过 SSL )。
Imports System
Imports System.ServiceProcess
Imports System.ComponentModel
Imports System.Configuration
Imports System.Configuration.Install
Imports System.ServiceModel
Imports System.ServiceModel.Description
Imports MSMSystemService.MSMServices
Imports MSMSystemService.Utilities
Public Class MSMServiceController
Dim sBAddress As Uri
Dim oSelfHost As ServiceHost 'New ServiceHost(GetType(DataServices), sBAddress)
Protected Overrides Sub OnStart(ByVal args() As String)
Dim oSetting As New MSMSettingManager
Dim oRegistry As New MSMRegistryManager
Dim oWSHttpBind As New BasicHttpBinding
Dim oSmb As ServiceMetadataBehavior
Dim sFilename As String
Dim sServiceURI As String
' Add code here to start your service. This method should set things
' in motion so your service can do its work.
Try
oRegistry.RegistryRootKey = SystemRegistryRoot.SystemLocalComputer
oRegistry.RegistryKeyPath = "SOFTWARE\MSMServices\DataService"
oRegistry.KeyName = "RootFolder"
oRegistry.ReadKey()
sFilename = oRegistry.keyValue
oSetting.SettingsFileName = Replace(sFilename & "\MSMServices.ini", "\\", "\")
oSetting.ApplicationName = "Service"
oSetting.KeyName = "URI"
sServiceURI = oSetting.ReadSettings()
If Trim(sServiceURI) <> "" Then
oWSHttpBind.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly
oWSHttpBind.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic
sBAddress = New Uri(sServiceURI)
oSelfHost = New ServiceHost(GetType(DataServices), sBAddress)
oSmb = oSelfHost.Description.Behaviors.Find(Of ServiceMetadataBehavior)()
If (oSmb Is Nothing) Then
oSmb = New ServiceMetadataBehavior
oSmb.HttpGetEnabled = True
oSelfHost.Description.Behaviors.Add(oSmb)
End If
oSelfHost.AddServiceEndpoint(GetType(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex")
oSelfHost.AddServiceEndpoint(GetType(IDataServices), oWSHttpBind, sBAddress)
oSelfHost.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = ServiceModel.Security.UserNamePasswordValidationMode.Custom
oSelfHost.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = New MSMServiceAuthentication()
oSelfHost.Open()
Else
EventLog.WriteEntry("MSM Data Service Error: Invalid URI Specified", EventLogEntryType.Error, 10255)
End If
Catch ex As Exception
EventLog.WriteEntry("MSM Data Service Error: " & ex.Message.ToString(), EventLogEntryType.Error, 10255)
End Try
End Sub
Protected Overrides Sub OnStop()
' Add code here to perform any tear-down necessary to stop your service.
If (oSelfHost IsNot Nothing) Then
If oSelfHost.State = CommunicationState.Opened Then
oSelfHost.Close()
End If
End If
End Sub
End Class
Windows 服务部分已完成,下一步是编译并测试代码。
请按照以下步骤安装和运行示例 Windows 服务。
1. 生成解决方案,并将编译后的 EXE 和程序集复制到一个文件夹。
2. 运行 MSMServiceUtilities.exe 来配置动态 URI 和数据库。
注意:在设置 URI 之前,请验证端口是否可用。
3. 首先单击“注册根目录”,然后单击“注册服务”。
第 4 步:从文件夹使用以下命令来安装/卸载 Windows 服务;
第 5 步:启动已安装的 Windows 服务并在事件查看器中验证状态。
事件查看器中的服务状态
客户端
创建一个新的 Windows 窗体应用程序项目,并设计一个带有所需字段的窗体;
向项目中添加以下引用;
Imports System.Net.Security
Imports System.ServiceModel
添加带有用户身份验证的服务引用;
此服务引用将创建指向我们的 DataServices Web 服务的WSDL 引用。
此示例客户端应用程序使用ChannelFactory 方法来创建通过自定义身份验证的 Http 流量,并部署了 BasicHttpBinding 类。
注意:开发人员可以通过从 INI 文件读取 URI 来使此客户端应用程序更具动态性。
Get 按钮的 Click 事件的代码。
Private Sub cmdGetStudent_Click(sender As Object, e As EventArgs) Handles cmdGetStudent.Click
Dim oWSHttp As New WSHttpBinding 'For Https access
Dim oBSHttp As New BasicHttpBinding 'For Http access
Dim oDSClient As IDataServices
Dim oURI As New Uri("http://192.168.1.92:9090/DataServices")
Dim oDSStudent As New StudentInfo
Dim oEndpoint As New EndpointAddress(oURI)
If Trim(txtStudentID.Text) <> "" Then
oBSHttp.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly
oBSHttp.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic
Dim oChFactory As New ChannelFactory(Of IDataServices)(oBSHttp, oEndpoint)
oChFactory.Credentials.UserName.UserName = "admin"
oChFactory.Credentials.UserName.Password = "admin"
oDSClient = oChFactory.CreateChannel()
oDSStudent = oDSClient.GetPupilData(Val(txtStudentID.Text))
txtFirstname.Text = oDSStudent.FirstName
txtMiddleName.Text = oDSStudent.MiddleName
txtLastname.Text = oDSStudent.LastName
txtGrnnumber.Text = oDSStudent.GRNNumber
txtGender.Text = ""
CType(oDSClient, IClientChannel).Close()
End If
End Sub
客户端编码部分已完成,您现在可以测试该应用程序了。
关注点
通过 HTTPS (SSL) 实现 WCF Web 服务可大大提高应用程序的安全性、可维护性、可扩展性和稳定性。
您的反馈始终受到欢迎。