通过 CRM 365 插件连接到 CRM Online
Connecting to CRM Online through CRM 365 Plugin
我需要通过 CRM 365 插件连接和检索 CRM Online 中的记录。我尝试使用 xrm.tooling.dll
简化连接,但不幸的是它显示 Could not load file or assembly 'microsoft.xrm.tooling.connector
,当我使用 ClientCredential
时,错误显示 Metadata contain refereces that cannot be resolved
.
奇怪的是,我在控制台应用程序中尝试了这两种方法,并且效果很好。只是想知道我在这种情况下想念什么?当我想通过插件连接到 CRM 时,我需要特殊要求吗?请任何人分享您的知识。
编辑
这只是一个示例代码,用于从 CRM Online 获取帐户名称并使用 InvalidPluginExecutionException 显示它:
IOrganizationService _service;
public void Execute(IServiceProvider serviceprovider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "opportunity")
return;
string connstring = @"Url=https://office.crm5.dynamics.com; Username=username@office.onmicrosoft.com; Password=crmoffice; authtype=Office365";
CrmServiceClient conn = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(connstring);
service = (IOrganizationService)conn.OrganizationWebProxyClient != null ? (IOrganizationService)conn.OrganizationWebProxyClient :
(IOrganizationService)conn.OrganizationServiceProxy;
try
{
Guid fabercastel = new Guid("efd566dc-10ff-e511-80df-c4346bdcddc1");
Entity _account = new Entity("account");
_account = service.Retrieve(_account.LogicalName, fabercastel, new ColumnSet("name"));
string x = _account["name"].ToString();
throw new InvalidPluginExecutionException("Result of Query : " + x);
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
您已经使用在插件第三行定义的 IOrganizationService 连接到 CRM。除非您需要连接到不同组织中的另一个 CRM 实例,否则不需要或不需要登录。
基本上把上面4行删掉就可以了
编辑:
public void Execute(IServiceProvider serviceprovider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "opportunity")
return;
Guid fabercastel = new Guid("efd566dc-10ff-e511-80df-c4346bdcddc1");
Entity _account = new Entity("account");
_account = service.Retrieve(_account.LogicalName, fabercastel, new ColumnSet("name"));
string x = _account["name"].ToString();
throw new InvalidPluginExecutionException("Result of Query : " + x);
}
}
您不需要任何额外的库,例如 Microsoft.Xrm.Tooling.Connector 或 SDK 中的其他库来使用 CRM Web 服务。与 SOAP / REST 协议相关的标准 .NET 机制就足够了(但当然这种方法可能会更难一些)。
编辑:我做了一些额外的调查,发现在不使用 SDK 库的情况下为 Office365 身份验证配置 auto-generated OrganizationServiceClient 可能真的很麻烦。我不是说这是不可能的,但微软没有记录。要添加更多详细信息,Visual Studio 生成的代理 类 不支持 OAuth 身份验证。
因此 - 我的第二个建议是使用 Facade Web 服务与 CRM OnLine 通信。您可以在 Windows Azure 或互联网上的任何其他 cloud/hosting 位置托管此 Web 服务。从您的 CRM 365 插件,您可以使用您的自定义 Web 服务方法并使用此服务与您的 CRM Online 实例通信。我想尝试 运行 连接到 CRM Online 的未记录方法会更好。**
您应该能够连接到另一个 CRM 实例,而无需使用在线沙盒之外的任何程序集(Microsoft.Xrm.Sdk 和相关程序除外)。只需使用来自 "SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs" 的 SDK 中的示例。连接到 Office365 的简化版本如下所示:
class AuthenticateWithNoHelp
{
private String _discoveryServiceAddress = "https://disco.crm.dynamics.com/XRMServices/2011/Discovery.svc";
private String _organizationUniqueName = "orgname";
private String _userName = "admin@orgname.onmicrosoft.com";
private String _password = "password";
private String _domain = "domain";
public void Run()
{
IServiceManagement<IDiscoveryService> serviceManagement =
ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
new Uri(_discoveryServiceAddress));
AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;
AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType);
String organizationUri = String.Empty;
using (DiscoveryServiceProxy discoveryProxy =
GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
{
if (discoveryProxy != null)
{
OrganizationDetailCollection orgs = DiscoverOrganizations(discoveryProxy);
organizationUri = FindOrganization(_organizationUniqueName,
orgs.ToArray()).Endpoints[EndpointType.OrganizationService];
}
}
if (!String.IsNullOrWhiteSpace(organizationUri))
{
IServiceManagement<IOrganizationService> orgServiceManagement =
ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
new Uri(organizationUri));
AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);
using (OrganizationServiceProxy organizationProxy =
GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
{
organizationProxy.EnableProxyTypes();
Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
new WhoAmIRequest())).UserId;
}
}
}
private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service, AuthenticationProviderType endpointType)
{
AuthenticationCredentials authCredentials = new AuthenticationCredentials();
authCredentials.ClientCredentials.UserName.UserName = _userName;
authCredentials.ClientCredentials.UserName.Password = _password;
return authCredentials;
}
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;
}
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.UrlName, orgUniqueName,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
orgDetail = detail;
break;
}
}
return orgDetail;
}
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);
return (TProxy)classType
.GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
.Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
}
return (TProxy)classType
.GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
.Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
}
static public void Main(string[] args)
{
AuthenticateWithNoHelp app = new AuthenticateWithNoHelp();
app.Run();
}
}
您可以通过删除 DiscoveryService 部分并直接调用来进一步简化它:
https://orgname.api.crm.dynamics.com/XRMServices/2011/Organization.svc
这应该适用于沙盒插件,因为它仅使用 Sdk 程序集。
您应该能够连接到另一个 CRM 实例,而无需使用在线沙盒之外的任何程序集(Microsoft.Xrm.Sdk
和相关程序除外)。
例如,只需使用来自 SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs
.
的 SDK 中的示例
我需要通过 CRM 365 插件连接和检索 CRM Online 中的记录。我尝试使用 xrm.tooling.dll
简化连接,但不幸的是它显示 Could not load file or assembly 'microsoft.xrm.tooling.connector
,当我使用 ClientCredential
时,错误显示 Metadata contain refereces that cannot be resolved
.
奇怪的是,我在控制台应用程序中尝试了这两种方法,并且效果很好。只是想知道我在这种情况下想念什么?当我想通过插件连接到 CRM 时,我需要特殊要求吗?请任何人分享您的知识。
编辑
这只是一个示例代码,用于从 CRM Online 获取帐户名称并使用 InvalidPluginExecutionException 显示它:
IOrganizationService _service;
public void Execute(IServiceProvider serviceprovider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "opportunity")
return;
string connstring = @"Url=https://office.crm5.dynamics.com; Username=username@office.onmicrosoft.com; Password=crmoffice; authtype=Office365";
CrmServiceClient conn = new Microsoft.Xrm.Tooling.Connector.CrmServiceClient(connstring);
service = (IOrganizationService)conn.OrganizationWebProxyClient != null ? (IOrganizationService)conn.OrganizationWebProxyClient :
(IOrganizationService)conn.OrganizationServiceProxy;
try
{
Guid fabercastel = new Guid("efd566dc-10ff-e511-80df-c4346bdcddc1");
Entity _account = new Entity("account");
_account = service.Retrieve(_account.LogicalName, fabercastel, new ColumnSet("name"));
string x = _account["name"].ToString();
throw new InvalidPluginExecutionException("Result of Query : " + x);
}
catch (Exception ex)
{
throw new InvalidPluginExecutionException(ex.Message);
}
您已经使用在插件第三行定义的 IOrganizationService 连接到 CRM。除非您需要连接到不同组织中的另一个 CRM 实例,否则不需要或不需要登录。
基本上把上面4行删掉就可以了
编辑:
public void Execute(IServiceProvider serviceprovider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceprovider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceprovider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity ent = (Entity)context.InputParameters["Target"];
if (ent.LogicalName != "opportunity")
return;
Guid fabercastel = new Guid("efd566dc-10ff-e511-80df-c4346bdcddc1");
Entity _account = new Entity("account");
_account = service.Retrieve(_account.LogicalName, fabercastel, new ColumnSet("name"));
string x = _account["name"].ToString();
throw new InvalidPluginExecutionException("Result of Query : " + x);
}
}
您不需要任何额外的库,例如 Microsoft.Xrm.Tooling.Connector 或 SDK 中的其他库来使用 CRM Web 服务。与 SOAP / REST 协议相关的标准 .NET 机制就足够了(但当然这种方法可能会更难一些)。
编辑:我做了一些额外的调查,发现在不使用 SDK 库的情况下为 Office365 身份验证配置 auto-generated OrganizationServiceClient 可能真的很麻烦。我不是说这是不可能的,但微软没有记录。要添加更多详细信息,Visual Studio 生成的代理 类 不支持 OAuth 身份验证。
因此 - 我的第二个建议是使用 Facade Web 服务与 CRM OnLine 通信。您可以在 Windows Azure 或互联网上的任何其他 cloud/hosting 位置托管此 Web 服务。从您的 CRM 365 插件,您可以使用您的自定义 Web 服务方法并使用此服务与您的 CRM Online 实例通信。我想尝试 运行 连接到 CRM Online 的未记录方法会更好。**
您应该能够连接到另一个 CRM 实例,而无需使用在线沙盒之外的任何程序集(Microsoft.Xrm.Sdk 和相关程序除外)。只需使用来自 "SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs" 的 SDK 中的示例。连接到 Office365 的简化版本如下所示:
class AuthenticateWithNoHelp
{
private String _discoveryServiceAddress = "https://disco.crm.dynamics.com/XRMServices/2011/Discovery.svc";
private String _organizationUniqueName = "orgname";
private String _userName = "admin@orgname.onmicrosoft.com";
private String _password = "password";
private String _domain = "domain";
public void Run()
{
IServiceManagement<IDiscoveryService> serviceManagement =
ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
new Uri(_discoveryServiceAddress));
AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;
AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType);
String organizationUri = String.Empty;
using (DiscoveryServiceProxy discoveryProxy =
GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
{
if (discoveryProxy != null)
{
OrganizationDetailCollection orgs = DiscoverOrganizations(discoveryProxy);
organizationUri = FindOrganization(_organizationUniqueName,
orgs.ToArray()).Endpoints[EndpointType.OrganizationService];
}
}
if (!String.IsNullOrWhiteSpace(organizationUri))
{
IServiceManagement<IOrganizationService> orgServiceManagement =
ServiceConfigurationFactory.CreateManagement<IOrganizationService>(
new Uri(organizationUri));
AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);
using (OrganizationServiceProxy organizationProxy =
GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials))
{
organizationProxy.EnableProxyTypes();
Guid userid = ((WhoAmIResponse)organizationProxy.Execute(
new WhoAmIRequest())).UserId;
}
}
}
private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service, AuthenticationProviderType endpointType)
{
AuthenticationCredentials authCredentials = new AuthenticationCredentials();
authCredentials.ClientCredentials.UserName.UserName = _userName;
authCredentials.ClientCredentials.UserName.Password = _password;
return authCredentials;
}
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;
}
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.UrlName, orgUniqueName,
StringComparison.InvariantCultureIgnoreCase) == 0)
{
orgDetail = detail;
break;
}
}
return orgDetail;
}
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);
return (TProxy)classType
.GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
.Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
}
return (TProxy)classType
.GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
.Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
}
static public void Main(string[] args)
{
AuthenticateWithNoHelp app = new AuthenticateWithNoHelp();
app.Run();
}
}
您可以通过删除 DiscoveryService 部分并直接调用来进一步简化它:
https://orgname.api.crm.dynamics.com/XRMServices/2011/Organization.svc
这应该适用于沙盒插件,因为它仅使用 Sdk 程序集。
您应该能够连接到另一个 CRM 实例,而无需使用在线沙盒之外的任何程序集(Microsoft.Xrm.Sdk
和相关程序除外)。
例如,只需使用来自 SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs
.