Исключение триггера CLR при попытке связаться со службой WCF - PullRequest
1 голос
/ 20 марта 2012

У меня есть CLR SQL Trigger, который пытается связаться со службой WCF на основе следующей статьи

Когда я пытаюсь обновить / вставить запись, я получаюследующее исключение:

No row was updated.    
The data in row 1 was not committed.    
Error Source: .Net SqlClient Data Provider.    
Error Message: A .NET Framework error occured during execution of a user-defined routine or aggregate "WCFTrigger": System.Security.HostProtectionException: Attempt to perform an operation that was forbidden by the CLR host.    
The protected resource (only available with full trust) where: All    
The demanded resources were: Synchronization, ExternalThreading    
System.Security.HostProtectionException:    
  at System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper(Type ContactType, Type ServiceType, Object serviceImplementation)    
  at System.ServiceModel.ChannelFactory '1.CreateDescription()    
  at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, 
EndpointAddress address)    
  at System.ServiceModel.ChannelFactory '1..ctor(Binding binding, EndpointAddress address)    
  at System.ServiceModel.ClientBase '1..ctor(Binding binding, EndpointAddress address)    
  at ServiceClient.WCFServiceReference.ServiceContractClient..ctor(Binding binding, 
EndpointAddress address)

Хост такой же, как в статье, клиент app.config:

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IServiceContract" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
                    <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
                    <security mode="Message">
                        <transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
                        <message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default"/>
                    </security>
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:8000/services/MyService" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IServiceContract" contract="WCFServiceReference.IServiceContract" name="WSHttpBinding_IServiceContract">
                <identity>
                    <userPrincipalName value="xxx@yyy.zzzt"/>
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
<startup><supportedRuntime version="v2.0.50727"/></startup></configuration>

Кто-нибудь знает, что это такое и почему?


Код триггера:

public partial class Triggers {
    [SqlProcedure()]
    public static void SendData( String crudType ) {
        EndpointAddress endpoint = new EndpointAddress( new Uri( "http://localhost:8000/services/myservice" ) );
        WSHttpBinding httpBinding = new WSHttpBinding();
        ServiceClient.WCFServiceReference.ServiceContractClient  myClient = new ServiceClient.WCFServiceReference.ServiceContractClient( httpBinding, endpoint );

            switch( crudType ) {
                case "Update":
                    myClient.UpdateOccured();
                    break;
                case "Insert":
                    myClient.InsertOccured();
                    break;
        }
    }

    [Microsoft.SqlServer.Server.SqlTrigger( Name = "WCFTrigger",
       Target = "tbCR", Event = "FOR UPDATE, INSERT" )]
    public static void Trigger1() {
        SqlTriggerContext myContext = SqlContext.TriggerContext;

        switch( myContext.TriggerAction ) {
            case TriggerAction.Update:
                SendData( "Update" );
                break;
            case TriggerAction.Insert:
                SendData( "Insert" );
                break;
        }
    }
}

Прокси:

namespace ServiceClient.WCFServiceReference {
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(ConfigurationName="WCFServiceReference.IServiceContract")]
    public interface IServiceContract {

        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IServiceContract/UpdateOccured", ReplyAction="http://tempuri.org/IServiceContract/UpdateOccuredResponse")]
        void UpdateOccured();

        [System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IServiceContract/InsertOccured", ReplyAction="http://tempuri.org/IServiceContract/InsertOccuredResponse")]
        void InsertOccured();
    }

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public interface IServiceContractChannel : ServiceClient.WCFServiceReference.IServiceContract, System.ServiceModel.IClientChannel {
    }

    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
    public partial class ServiceContractClient : System.ServiceModel.ClientBase<ServiceClient.WCFServiceReference.IServiceContract>, ServiceClient.WCFServiceReference.IServiceContract {

        public ServiceContractClient() {
        }

        public ServiceContractClient(string endpointConfigurationName) : 
                base(endpointConfigurationName) {
        }

        public ServiceContractClient(string endpointConfigurationName, string remoteAddress) : 
                base(endpointConfigurationName, remoteAddress) {
        }

        public ServiceContractClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(endpointConfigurationName, remoteAddress) {
        }

        public ServiceContractClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) : 
                base(binding, remoteAddress) {
        }

        public void UpdateOccured() {
            base.Channel.UpdateOccured();
        }

        public void InsertOccured() {
            base.Channel.InsertOccured();
        }
    }
}

Ответы [ 2 ]

2 голосов
/ 20 марта 2012

Проблема вызвана запуском кода .NET (служба вызова клиента WCF) в SQL Server с параметром безопасности доступа с частичным доверительным кодом (CAS).Посмотрите эту статью MSDN о настройке CAS для SQL Server.

EDIT:

В качестве альтернативы включению полного доверия настройте конечную точку webHttpBinding в службе WCF.Вызовите службу, используя классы System.Net HttpWebRequest & HttpWebResponse , чтобы избежать использования сантехники на основе WCF ChannelFactory.

1 голос
/ 20 марта 2012

Вы не можете делать что-либо многопоточное в любых сборках SQLCLR, и исключение говорит вам, что вы пытаетесь использовать многопоточность.Вы вызываете службу WCF асинхронно?

Я бы рекомендовал публиковать ваш код из триггера SQLCLR для получения дополнительной помощи.

Вызов служб WCF из SQL CLR намного сложнее, чем вызов веб-служб asmx, вы уверены, что вам нужен wcf?

...