65.9K
CodeProject 正在变化。 阅读更多。
Home

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

2015年8月30日

CPOL

5分钟阅读

viewsIcon

27715

downloadIcon

16

自托管 WCF 服务作为具有自定义用户身份验证的 Windows 服务(通过 Http)。

下载源文件 MSMSystemServices.rar

引言

在本文中,我想演示一个非常简单的 WCF 服务器/客户端应用程序,但此演示应用程序旨在演示自托管服务。您可能会问“什么是自托管?”。让我详细解释一下。

有两种托管 WCF 服务的方法:

1. 使用 IIS 托管:托管 WCF Web 服务的传统方式。

2. 自托管:一种无需 IIS 即可托管服务的方法。  

什么是自托管?

在托管应用程序中托管服务称为自托管服务。托管应用程序可以是控制台应用程序、Windows 窗体应用程序、WPF 或 Windows 服务。请查看此 MSDN 链接了解更多详情,并查看此 MSDN 链接中的示例代码。

在 asp.net 论坛上,对此自托管服务与 IIS 托管服务之间的差异进行了详细讨论。

让我们继续讨论 WCF;

WCF 有两个区域

  1. 服务
  2. 客户端

1. 服务

使服务可用的基本步骤。

  1. 定义服务协定
  2. 实现服务协定
  3. 托管并运行服务协定 

2. 客户端 

WCF 客户端是一个可以像调用方法一样与 WCF 服务操作进行通信的应用程序。

动态 WCF 客户端与服务的通信分为三个步骤:

  1. 使用通道工厂类(System.ServiceModel.ChannelFactory)创建 WCF 客户端
  2. 配置 WCF 客户端
  3. 使用 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 服务可大大提高应用程序的安全性、可维护性、可扩展性和稳定性。

您的反馈始终受到欢迎。 

© . All rights reserved.