Практическое руководство. Установка свойства ProtectionLevel
Уровень защиты можно задать, применив соответствующий атрибут и задав свойство. Защиту на уровне службы можно задать таким образом, чтобы она влияла на все части каждого сообщения, можно также задать защиту на более детализированных уровнях - от методов до частей сообщения. Дополнительные сведения о свойстве ProtectionLevel
см. в разделе "Общие сведения о уровне защиты".
Примечание.
Уровни защиты можно задавать только в коде, а не в конфигурации.
Подписание всех сообщений для службы
Создайте интерфейс для службы.
Примените к службе атрибут 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
Подписание всех частей сообщения для операции
Создайте интерфейс для службы и примените к нему атрибут ServiceContractAttribute.
Добавьте в интерфейс объявление метода.
Примените к методу атрибут 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. Дополнительные сведения о создании строго типизированных ошибок см. в разделе "Указание и обработка ошибок в контрактах и службах " и "Практическое руководство. Объявление сбоев в контрактах служб".
Защита сообщения об ошибке
Создайте тип, представляющий сообщение об ошибке. В следующем примере описано создание класса, именуемого
MathFault
, с двумя полями.Примените к типу атрибут 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
Примените атрибут FaultContractAttribute к методу, который будет возвращать ошибку, и настройте параметр
detailType
к типу класса ошибки в интерфейсе, который будет возвращать ошибку,Задайте для свойства 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
Защита частей сообщения
Для защиты частей сообщения следует использовать контракт сообщения. Дополнительные сведения о контрактах сообщений см. в разделе "Использование контрактов сообщений".
Защита тела сообщения
Создайте тип, представляющий сообщение. В следующем примере описано создание класса
Company
двумя полями:CompanyName
иCompanyID
.Примените атрибут MessageContractAttribute к классу и задайте значение ProtectionLevel для свойства EncryptAndSign.
Примените атрибут MessageHeaderAttribute к полю, которое будет выражено как заголовок сообщения, и задайте значение
ProtectionLevel
для свойства EncryptAndSign.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 = {0}", cd.Name, cd.ProtectionLevel);
foreach (OperationDescription od in cd.Operations)
{
Console.WriteLine("\nOperationDescription: Name = {0}", od.Name, od.ProtectionLevel);
Console.WriteLine("ProtectionLevel = {1}", od.Name, od.ProtectionLevel);
foreach (MessageDescription m in od.Messages)
{
Console.WriteLine("\t {0}: {1}", m.Action, m.ProtectionLevel);
foreach (MessageHeaderDescription mh in m.Headers)
{
Console.WriteLine("\t\t {0}: {1}", mh.Name, mh.ProtectionLevel);
foreach (MessagePropertyDescription mp in m.Properties)
{
Console.WriteLine("{0}: {1}", 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