Как установить свойство ProtectionLevel

Уровень защиты можно задать, применив соответствующий атрибут и задав свойство. Вы можете настроить защиту на уровне обслуживания, чтобы повлиять на все части каждого сообщения или настроить защиту на все более детализированных уровнях, от методов до частей сообщения. Дополнительные сведения о свойстве ProtectionLevel см. в разделе Общие сведения о уровне защиты.

Примечание.

Уровни защиты можно задать только в коде, а не в конфигурации.

Подписывать все сообщения для сервиса

  1. Создайте интерфейс для службы.

  2. Примените атрибут ServiceContractAttribute к службе и задайте для свойства ProtectionLevel значение Sign, как показано в следующем коде (уровень по умолчанию — EncryptAndSign).

    // Set the ProtectionLevel on the whole service to Sign.
    [ServiceContract(ProtectionLevel = ProtectionLevel.Sign)]
    public interface ICalculator
    
    ' Set the ProtectionLevel on the whole service to Sign.
    <ServiceContract(ProtectionLevel:=ProtectionLevel.Sign)> _
    Public Interface ICalculator
    

Чтобы подписать все части сообщения для операции

  1. Создайте интерфейс для службы и примените атрибут ServiceContractAttribute к интерфейсу.

  2. Добавьте объявление метода в интерфейс.

  3. Примените атрибут OperationContractAttribute к методу и задайте для свойства ProtectionLevel значение Sign, как показано в следующем коде.

    // Set the ProtectionLevel on the whole service to Sign.
    [ServiceContract(ProtectionLevel = ProtectionLevel.Sign)]
    public interface ICalculator
    {
        // Set the ProtectionLevel on this operation to None.
        [OperationContract(ProtectionLevel = ProtectionLevel.Sign)]
        double Add(double a, double b);
    }
    
    ' Set the ProtectionLevel on the whole service to Sign.
    <ServiceContract(ProtectionLevel:=ProtectionLevel.Sign)> _
    Public Interface ICalculator
    
        ' Set the ProtectionLevel on this operation to Sign.
        <OperationContract(ProtectionLevel:=ProtectionLevel.Sign)> _
        Function Add(ByVal a As Double, ByVal b As Double) As Double
    End Interface
    

Защита сообщений об ошибках

Исключения, которые возникают в службе, могут быть отправлены клиенту в виде ошибок SOAP. Дополнительные сведения о создании строго типизированных ошибок см. в разделах Указание и обработка ошибок в контрактах и службах и Как объявить ошибки в контрактах служб.

Защита сообщения об ошибке

  1. Создайте тип, представляющий сообщение об ошибке. В следующем примере создается класс с именем MathFault с двумя полями.

  2. Примените атрибут DataContractAttribute к типу и атрибуту DataMemberAttribute к каждому полю, которое должно быть сериализовано, как показано в следующем коде.

    [DataContract]
    public class MathFault
    {
        [DataMember]
        public string operation;
        [DataMember]
        public string description;
    }
    
    <DataContract()> _
    Public Class MathFault
        <DataMember()> _
        Public operation As String
        <DataMember()> _
        Public description As String
    End Class
    
  3. В интерфейсе, который вернет ошибку, примените атрибут FaultContractAttribute к методу, который вернет ошибку и присвоит параметру detailType тип класса сбоя.

  4. Кроме того, в конструкторе задайте для свойства ProtectionLevel значение EncryptAndSign, как показано в следующем коде.

    public interface ICalculator
    {
        // Set the ProtectionLevel on a FaultContractAttribute.
        [OperationContract(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
        [FaultContract(
            typeof(MathFault),
            Action = @"http://localhost/Add",
            Name = "AddFault",
            Namespace = "http://contoso.com",
            ProtectionLevel = ProtectionLevel.EncryptAndSign)]
        double Add(double a, double b);
    }
    
    Public Interface ICalculator
        ' Set the ProtectionLevel on a FaultContractAttribute.
        <OperationContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign), _
         FaultContract(GetType(MathFault), ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
        Function Add(ByVal a As Double, ByVal b As Double) As Double
    End Interface
    

Защита частей сообщений

Используйте контракт сообщения для защиты частей сообщения. Дополнительные сведения о контрактах сообщений см. в разделе Использование контрактов сообщений.

Чтобы защитить тело сообщения

  1. Создайте тип, представляющий сообщение. В следующем примере создается класс Company с двумя полями, CompanyName и CompanyID.

  2. Примените атрибут MessageContractAttribute к классу и задайте для свойства ProtectionLevel значение EncryptAndSign.

  3. Примените атрибут MessageHeaderAttribute к полю, которое будет выражено в виде заголовка сообщения и задайте для свойства ProtectionLevel значение EncryptAndSign.

  4. Примените MessageBodyMemberAttribute к любому полю, которое будет выражено как часть текста сообщения, и задайте для свойства ProtectionLevel значение EncryptAndSign, как показано в следующем примере.

    [MessageContract(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
    public class Company
    {
        [MessageHeader(ProtectionLevel = ProtectionLevel.Sign)]
        public string CompanyName;
    
        [MessageBodyMember(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
        public string CompanyID;
    }
    
    <MessageContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
    Public Class Company
        <MessageHeader(ProtectionLevel:=ProtectionLevel.Sign)> _
        Public CompanyName As String
    
        <MessageBodyMember(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
        Public CompanyID As String
    End Class
    

Пример

В следующем примере задается свойство ProtectionLevel нескольких классов атрибутов в различных местах службы.

[ServiceContract(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public interface ICalculator
{
    [OperationContract(ProtectionLevel = ProtectionLevel.Sign)]
    double Add(double a, double b);

    [OperationContract()]
    [FaultContract(typeof(MathFault),
        ProtectionLevel = ProtectionLevel.EncryptAndSign)]
    double Subtract(double a, double b);

    [OperationContract(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
    Company GetCompanyInfo();
}

[DataContract]
public class MathFault
{
    [DataMember]
    public string operation;
    [DataMember]
    public string description;
}

[MessageContract(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public class Company
{
    [MessageHeader(ProtectionLevel = ProtectionLevel.Sign)]
    public string CompanyName;

    [MessageBodyMember(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
    public string CompanyID;
}

[MessageContract(ProtectionLevel = ProtectionLevel.Sign)]
public class Calculator : ICalculator
{
    public double Add(double a, double b)
    {
        return a + b;
    }

    public double Subtract(double a, double b)
    {
        return a - b;
    }

    public Company GetCompanyInfo()
    {
        Company co = new Company();
        co.CompanyName = "www.cohowinery.com";
        return co;
    }
}

public class Test
{
    static void Main()
    {
        Test t = new Test();
        try
        {
            t.Run();
        }
        catch (System.InvalidOperationException inv)
        {
            Console.WriteLine(inv.Message);
        }
    }

    private void Run()
    {
        // Create a binding and set the security mode to Message.
        WSHttpBinding b = new WSHttpBinding();
        b.Security.Mode = SecurityMode.Message;

        Type contractType = typeof(ICalculator);
        Type implementedContract = typeof(Calculator);
        Uri baseAddress = new Uri("http://localhost:8044/base");

        // Create the ServiceHost and add an endpoint.
        ServiceHost sh = new ServiceHost(implementedContract, baseAddress);
        sh.AddServiceEndpoint(contractType, b, "Calculator");

        ServiceMetadataBehavior sm = new ServiceMetadataBehavior();
        sm.HttpGetEnabled = true;
        sh.Description.Behaviors.Add(sm);
        sh.Credentials.ServiceCertificate.SetCertificate(
            StoreLocation.CurrentUser,
            StoreName.My,
            X509FindType.FindByIssuerName,
            "ValidCertificateIssuer");

        foreach (ServiceEndpoint se in sh.Description.Endpoints)
        {
            ContractDescription cd = se.Contract;
            Console.WriteLine($"\nContractDescription: ProtectionLevel = {cd.Name}");
            foreach (OperationDescription od in cd.Operations)
            {
                Console.WriteLine($"\nOperationDescription: Name = {od.Name}");
                Console.WriteLine($"ProtectionLevel = {od.ProtectionLevel}");
                foreach (MessageDescription m in od.Messages)
                {
                    Console.WriteLine($"\t {m.Action}: {m.ProtectionLevel}");
                    foreach (MessageHeaderDescription mh in m.Headers)
                    {
                        Console.WriteLine($"\t\t {mh.Name}: {mh.ProtectionLevel}");

                        foreach (MessagePropertyDescription mp in m.Properties)
                        {
                            Console.WriteLine($"{mp.Name}: {mp.ProtectionLevel}");
                        }
                    }
                }
            }
        }
        sh.Open();
        Console.WriteLine("Listening");
        Console.ReadLine();
        sh.Close();
    }
}
<ServiceContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
Public Interface ICalculator
    <OperationContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
    Function Add(ByVal a As Double, ByVal b As Double) As Double


    <OperationContract(), _
       FaultContract _
       (GetType(MathFault), _
       Action:="http://localhost/Add", _
       Name:="AddFault", _
       Namespace:="http://contoso.com", _
       ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
    Function Subtract(ByVal a As Double, ByVal b As Double) As Double

    <OperationContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
    Function GetCompanyInfo() As Company
End Interface


<DataContract()> _
Public Class MathFault
    <DataMember()> _
    Public operation As String
    <DataMember()> _
    Public description As String
End Class

<MessageContract(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
Public Class Company
    <MessageHeader(ProtectionLevel:=ProtectionLevel.Sign)> _
    Public CompanyName As String

    <MessageBodyMember(ProtectionLevel:=ProtectionLevel.EncryptAndSign)> _
    Public CompanyID As String
End Class

<MessageContract(ProtectionLevel:=ProtectionLevel.Sign)> _
Public Class Calculator
    Implements ICalculator

    Public Function Add(ByVal a As Double, ByVal b As Double) As Double _
      Implements ICalculator.Add
        Return a + b

    End Function

    Public Function Subtract(ByVal a As Double, ByVal b As Double) As Double _
       Implements ICalculator.Subtract
        Return a - b

    End Function

    Public Function GetCompanyInfo() As Company Implements ICalculator.GetCompanyInfo
        Dim co As New Company()
        co.CompanyName = "www.cohowinery.com"
        Return co
    End Function
End Class


Public Class Test

    Shared Sub Main()
        Dim t As New Test()
        Try
            t.Run()
        Catch inv As System.InvalidOperationException
            Console.WriteLine(inv.Message)
        End Try
    End Sub


    Private Sub Run()
        ' Create a binding and set the security mode to Message.
        Dim b As New WSHttpBinding()
        b.Security.Mode = SecurityMode.Message

        Dim contractType As Type = GetType(ICalculator)
        Dim implementedContract As Type = GetType(Calculator)
        Dim baseAddress As New Uri("http://localhost:8044/base")

        ' Create the ServiceHost and add an endpoint.
        Dim sh As New ServiceHost(implementedContract, baseAddress)
        sh.AddServiceEndpoint(contractType, b, "Calculator")

        Dim sm As New ServiceMetadataBehavior()
        sm.HttpGetEnabled = True
        sh.Description.Behaviors.Add(sm)
        sh.Credentials.ServiceCertificate.SetCertificate( _
           StoreLocation.CurrentUser, StoreName.My, _
           X509FindType.FindByIssuerName, "ValidCertificateIssuer")

        Dim se As ServiceEndpoint
        For Each se In sh.Description.Endpoints
            Dim cd As ContractDescription = se.Contract
            Console.WriteLine(vbLf + "ContractDescription: ProtectionLevel = {0}", _
               cd.Name, cd.ProtectionLevel)
            Dim od As OperationDescription
            For Each od In cd.Operations
                Console.WriteLine(vbLf + "OperationDescription: Name = {0}", od.Name, od.ProtectionLevel)
                Console.WriteLine("ProtectionLevel = {1}", od.Name, od.ProtectionLevel)
                Dim m As MessageDescription
                For Each m In od.Messages
                    Console.WriteLine(vbTab + " {0}: {1}", m.Action, m.ProtectionLevel)
                    Dim mh As MessageHeaderDescription
                    For Each mh In m.Headers
                        Console.WriteLine(vbTab + vbTab + " {0}: {1}", mh.Name, mh.ProtectionLevel)

                        Dim mp As MessagePropertyDescription
                        For Each mp In m.Properties
                            Console.WriteLine("{0}: {1}", mp.Name, mp.ProtectionLevel)
                        Next mp
                    Next mh
                Next m
            Next od
        Next se
        sh.Open()
        Console.WriteLine("Listening")
        Console.ReadLine()
        sh.Close()

    End Sub
End Class

Компиляция кода

В следующем коде показаны пространства имен, необходимые для компиляции примера кода.

using System;
using System.ServiceModel;
using System.Net.Security;
using System.ServiceModel.Description;
using System.Security.Cryptography.X509Certificates;
using System.Runtime.Serialization;
Imports System.ServiceModel
Imports System.Net.Security
Imports System.ServiceModel.Description
Imports System.Security.Cryptography.X509Certificates
Imports System.Runtime.Serialization

См. также