Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/wcf/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 正在IClientMessageInspector中获取当前IpluginContext或IOOrganizationService对象_C#_Wcf_Dynamics Crm_Crm_Microsoft Dynamics - Fatal编程技术网

C# 正在IClientMessageInspector中获取当前IpluginContext或IOOrganizationService对象

C# 正在IClientMessageInspector中获取当前IpluginContext或IOOrganizationService对象,c#,wcf,dynamics-crm,crm,microsoft-dynamics,C#,Wcf,Dynamics Crm,Crm,Microsoft Dynamics,我正在开发一个插件,它调用另一个应用程序WCF服务并解析响应。一切正常,但在记录xml消息时,我面临许多问题 我使用了一个截取器,具有以下签名: public class SFACMessageInspector : IEndpointBehavior, IClientMessageInspector 必须实施以下方法: public object BeforeSendRequest(ref Message request,IClientChannel channel) public void

我正在开发一个插件,它调用另一个应用程序WCF服务并解析响应。一切正常,但在记录xml消息时,我面临许多问题

我使用了一个截取器,具有以下签名:

public class SFACMessageInspector : IEndpointBehavior, IClientMessageInspector
必须实施以下方法:

public object BeforeSendRequest(ref Message request,IClientChannel channel)
public void AfterReceiveReply(ref Message reply,object correlationState)
在这些方法中,我检索xml消息没有问题,但现在我需要记录它们,因此有人要求我创建一个新的记录器实体,该实体在两个字段上同时包含请求和响应

最大的问题是我没有以下任何对象:

IOrganizationService service //this is the object I could use to create the entity
IPluginExecutionContext context  //the context of the plugin, from this I can create a new IorganizationService
作为拦截器,我无法将它们作为参数传递,因此我考虑了两种选择,它们都没有给我预期的结果:

  • 将服务或上下文声明为静态类变量(例如,从插件调用类),以便我可以从检查器访问它。我真的不喜欢这种方法,因为上下文是我能想到的不那么静态的对象,它可能会在CRM这样的多用户环境中产生问题

  • 在给定字符串连接参数的情况下创建新的IOOrganizationService对象。我在
    Microsoft.Xrm.Client
    库中找到了唯一的工作对象,不幸的是,该库已弃用,我可以在其中创建一个新对象,如:

var_service=neworganizationservice(CrmConnection.Parse(CRMConnectionString))

我使用它一个月左右都没有问题,但将我的Dynamics CRM迁移到2016版本后,它就不再有效了。当调用代码为创建服务的
LogIntegrationMessage
方法时,将引发以下异常,并显示以下一般错误消息:

Inner Exception: Microsoft.Xrm.Sdk.InvalidPluginExecutionException: The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.
内部异常:Microsoft.Xrm.Sdk.InvalidPluginExecutionException:由于内部错误,服务器无法处理请求。有关错误的详细信息,请在服务器上启用IncludeExceptionDetailInFaults(从ServiceBehaviorAttribute或从配置行为),以便将异常信息发送回客户端,或者根据Microsoft.NET Framework SDK文档启用跟踪,并检查服务器跟踪日志。
我能做什么?在我没有PluginContext或OrganizationService的拦截器类中,有没有其他方法来创建实例


提前感谢CRM 2016中的事件,您应该能够使用普通的旧OrganizationServiceProxy类手动连接到CRM(事实上,您使用的OrganizationService类只是该类的包装器)。回到CRM 2011年,我们都是这样连接到CRM的,网上有很多例子。CRM SDK(自2011年、2016年以来的所有版本都有相同的版本)下的“\SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.CS”提供了一个很好的验证示例:

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Reflection;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using Microsoft.Crm.Sdk.Messages;

namespace Microsoft.Crm.Sdk.Samples
{
    /// <summary>
    /// Demonstrate how to do basic authentication using IServiceManagement and SecurityTokenResponse.
    /// </summary>
    class AuthenticateWithNoHelp
    {
        #region Class Level Members
        // To get discovery service address and organization unique name, 
        // Sign in to your CRM org and click Settings, Customization, Developer Resources.
        // On Developer Resource page, find the discovery service address under Service Endpoints and organization unique name under Your Organization Information.
        private String _discoveryServiceAddress = "https://dev.crm.dynamics.com/XRMServices/2011/Discovery.svc";
        private String _organizationUniqueName = "OrganizationUniqueName";
        // Provide your user name and password.
        private String _userName = "username@mydomain.com";
        private String _password = "password"
    #endregion Class Level Members

    #region How To Sample Code
    /// <summary>
    /// 
    /// </summary>
    public void Run()
    {
        //<snippetAuthenticateWithNoHelp1>
        IServiceManagement<IDiscoveryService> serviceManagement =
                    ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
                    new Uri(_discoveryServiceAddress));
        AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;

        // Set the credentials.
        AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType);


        String organizationUri = String.Empty;
        // Get the discovery service proxy.
        using (DiscoveryServiceProxy discoveryProxy =
            GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
        {
            // Obtain organization information from the Discovery service. 
            if (discoveryProxy != null)
            {
                // Obtain information about the organizations that the system user belongs to.
                OrganizationDetailCollection orgs = DiscoverOrganizations(discoveryProxy);
                // Obtains the Web address (Uri) of the target organization.
                organizationUri = FindOrganization(_organizationUniqueName,
                    orgs.ToArray()).Endpoints[EndpointType.OrganizationService];

            }
        }
        //</snippetAuthenticateWithNoHelp1>


        if (!String.IsNullOrWhiteSpace(organizationUri))
        {
            //<snippetAuthenticateWithNoHelp3>
            IServiceManagement<IOrganizationService> orgServiceManagement =
                ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
                new Uri(organizationUri));

            // Set the credentials.
            AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);

            // Get the organization service proxy.
            using (OrganizationServiceProxy organizationProxy =
                GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
            {
                // This statement is required to enable early-bound type support.
                organizationProxy.EnableProxyTypes();

                // Now make an SDK call with the organization service proxy.
                // Display information about the logged on user.
                Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
                    new WhoAmIRequest())).UserId;
                SystemUser systemUser = organizationProxy.Retrieve("systemuser", userid,
                    new ColumnSet(new string[] { "firstname", "lastname" })).ToEntity<SystemUser>();
                Console.WriteLine("Logged on user is {0} {1}.",
                    systemUser.FirstName, systemUser.LastName);
            }
            //</snippetAuthenticateWithNoHelp3>
        }

    }

    //<snippetAuthenticateWithNoHelp2>
    /// <summary>
    /// Obtain the AuthenticationCredentials based on AuthenticationProviderType.
    /// </summary>
    /// <param name="service">A service management object.</param>
    /// <param name="endpointType">An AuthenticationProviderType of the CRM environment.</param>
    /// <returns>Get filled credentials.</returns>
    private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service, AuthenticationProviderType endpointType)
    {
        AuthenticationCredentials authCredentials = new AuthenticationCredentials();

        switch (endpointType)
        {
            case AuthenticationProviderType.ActiveDirectory:
                authCredentials.ClientCredentials.Windows.ClientCredential =
                    new System.Net.NetworkCredential(_userName,
                        _password,
                        _domain);
                break;
            case AuthenticationProviderType.LiveId:
                authCredentials.ClientCredentials.UserName.UserName = _userName;
                authCredentials.ClientCredentials.UserName.Password = _password;
                authCredentials.SupportingCredentials = new AuthenticationCredentials();
                authCredentials.SupportingCredentials.ClientCredentials =
                    Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
                break;
            default: // For Federated and OnlineFederated environments.                    
                authCredentials.ClientCredentials.UserName.UserName = _userName;
                authCredentials.ClientCredentials.UserName.Password = _password;
                // For OnlineFederated single-sign on, you could just use current UserPrincipalName instead of passing user name and password.
                // authCredentials.UserPrincipalName = UserPrincipal.Current.UserPrincipalName;  // Windows Kerberos

                // The service is configured for User Id authentication, but the user might provide Microsoft
                // account credentials. If so, the supporting credentials must contain the device credentials.
                if (endpointType == AuthenticationProviderType.OnlineFederation)
                {
                    IdentityProvider provider = service.GetIdentityProvider(authCredentials.ClientCredentials.UserName.UserName);
                    if (provider != null && provider.IdentityProviderType == IdentityProviderType.LiveId)
                    {
                        authCredentials.SupportingCredentials = new AuthenticationCredentials();
                        authCredentials.SupportingCredentials.ClientCredentials =
                            Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
                    }
                }

                break;
        }

        return authCredentials;
    }
    //</snippetAuthenticateWithNoHelp2>

    /// <summary>
    /// Discovers the organizations that the calling user belongs to.
    /// </summary>
    /// <param name="service">A Discovery service proxy instance.</param>
    /// <returns>Array containing detailed information on each organization that 
    /// the user belongs to.</returns>
    public OrganizationDetailCollection DiscoverOrganizations(
        IDiscoveryService service)
    {
        if (service == null) throw new ArgumentNullException("service");
        RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
        RetrieveOrganizationsResponse orgResponse =
            (RetrieveOrganizationsResponse)service.Execute(orgRequest);

        return orgResponse.Details;
    }

    /// <summary>
    /// Finds a specific organization detail in the array of organization details
    /// returned from the Discovery service.
    /// </summary>
    /// <param name="orgUniqueName">The unique name of the organization to find.</param>
    /// <param name="orgDetails">Array of organization detail object returned from the discovery service.</param>
    /// <returns>Organization details or null if the organization was not found.</returns>
    /// <seealso cref="DiscoveryOrganizations"/>
    public OrganizationDetail FindOrganization(string orgUniqueName,
        OrganizationDetail[] orgDetails)
    {
        if (String.IsNullOrWhiteSpace(orgUniqueName))
            throw new ArgumentNullException("orgUniqueName");
        if (orgDetails == null)
            throw new ArgumentNullException("orgDetails");
        OrganizationDetail orgDetail = null;

        foreach (OrganizationDetail detail in orgDetails)
        {
            if (String.Compare(detail.UniqueName, orgUniqueName,
                StringComparison.InvariantCultureIgnoreCase) == 0)
            {
                orgDetail = detail;
                break;
            }
        }
        return orgDetail;
    }

    /// <summary>
    /// Generic method to obtain discovery/organization service proxy instance.
    /// </summary>
    /// <typeparam name="TService">
    /// Set IDiscoveryService or IOrganizationService type to request respective service proxy instance.
    /// </typeparam>
    /// <typeparam name="TProxy">
    /// Set the return type to either DiscoveryServiceProxy or OrganizationServiceProxy type based on TService type.
    /// </typeparam>
    /// <param name="serviceManagement">An instance of IServiceManagement</param>
    /// <param name="authCredentials">The user's Microsoft Dynamics CRM logon credentials.</param>
    /// <returns></returns>
    /// <snippetAuthenticateWithNoHelp4>
    private TProxy GetProxy<TService, TProxy>(
        IServiceManagement<TService> serviceManagement,
        AuthenticationCredentials authCredentials)
        where TService : class
        where TProxy : ServiceProxy<TService>
    {
        Type classType = typeof(TProxy);

        if (serviceManagement.AuthenticationType !=
            AuthenticationProviderType.ActiveDirectory)
        {
            AuthenticationCredentials tokenCredentials =
                serviceManagement.Authenticate(authCredentials);
            // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. 
            // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
            return (TProxy)classType
                .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
                .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
        }

        // Obtain discovery/organization service proxy for ActiveDirectory environment.
        // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
        return (TProxy)classType
            .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
            .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
    }
    /// </snippetAuthenticateWithNoHelp4>

    #endregion How To Sample Code

    #region Main method

    /// <summary>
    /// Standard Main() method used by most SDK samples.
    /// </summary>
    /// <param name="args"></param>
    static public void Main(string[] args)
    {
        try
        {
            AuthenticateWithNoHelp app = new AuthenticateWithNoHelp();
            app.Run();
        }
        catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)
        {
            Console.WriteLine("The application terminated with an error.");
            Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp);
            Console.WriteLine("Code: {0}", ex.Detail.ErrorCode);
            Console.WriteLine("Message: {0}", ex.Detail.Message);
            Console.WriteLine("Trace: {0}", ex.Detail.TraceText);
            Console.WriteLine("Inner Fault: {0}",
                null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
        }
        catch (System.TimeoutException ex)
        {
            Console.WriteLine("The application terminated with an error.");
            Console.WriteLine("Message: {0}", ex.Message);
            Console.WriteLine("Stack Trace: {0}", ex.StackTrace);
            Console.WriteLine("Inner Fault: {0}",
                null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message);
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("The application terminated with an error.");
            Console.WriteLine(ex.Message);

            // Display the details of the inner exception.
            if (ex.InnerException != null)
            {
                Console.WriteLine(ex.InnerException.Message);

                FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException
                    as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>;
                if (fe != null)
                {
                    Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp);
                    Console.WriteLine("Code: {0}", fe.Detail.ErrorCode);
                    Console.WriteLine("Message: {0}", fe.Detail.Message);
                    Console.WriteLine("Trace: {0}", fe.Detail.TraceText);
                    Console.WriteLine("Inner Fault: {0}",
                        null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
                }
            }
        }
        // Additional exceptions to catch: SecurityTokenValidationException, ExpiredSecurityTokenException,
        // SecurityAccessDeniedException, MessageSecurityException, and SecurityNegotiationException.

        finally
        {
            Console.WriteLine("Press <Enter> to exit.");
            Console.ReadLine();
        }
    }
    #endregion Main method
}

可以添加IOOrganizationService字段和构造函数,以便在实例化时添加服务:

public class SFACMessageInspector : IEndpointBehavior, IClientMessageInspector
{
    private IOrganizationService service;

    public SFACMessageInspector(IOrganizationService svc)
    {
        service = svc;
    }
}
然后从插件中实例化:

public void Execute(IServiceProvider serviceProvider)
{
    var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    var factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
    var crmService = factory.CreateOrganizationService(context.UserId);

    var interceptor = new SFACMessageInspector(crmService);
}
然后,您应该能够在
BeforeSendRequest
AfterReceiveReply
方法中访问
服务
,而无需将其作为参数传入

如果您仍然希望使用连接字符串方法,那么新的方法是通过Xrm.Tooling.Connector程序集中的CrmServiceClient:

例如:

private IOrganizationService createService(string connectionString)
{
    return new CrmServiceClient(connectionString);
}

嗨,Pawel,我很感谢你的回答,但它有两个问题:1)我不能在每次需要在CRM上记录消息时都实例化这样一个长的过程。2) 我无法在代码中绑定凭据和url,因为我无法将其从开发环境更改为生产环境:这些参数中的任何一个都存储在CRM中的实体中,很明显,我需要一个工作服务来阅读它们…这不是最初问题的一部分,所以我认为您已经了解了这一点-在以前的解决方案中,您在哪里存储了CRMConnectionString?因为如果之前的解决方案对您有效,那么这是完全相同的。正如我所说,您之前实例化的OrganizationService正在执行与我在回答中发布的相同的逻辑—它只是从连接字符串中获取所有必要的数据,但在引擎盖下,连接看起来与上面完全相同(因此使用适当的参数实例化organizationServiceProxy)。也许可以分享你的连接字符串?还有一件事-我同意你在CRM中登录时不应该这样做,但你在最初的解决方案中就这么做了,StackOverflow不是一个抱怨别人坏主意的地方,而是解决问题的地方。很抱歉,现在它不是一行代码,但它对性能的影响与之前使用CRMConnectionString版本时完全相同。
private IOrganizationService createService(string connectionString)
{
    return new CrmServiceClient(connectionString);
}