Answered by:
CRM 2011 Online Early Binding Plug-in

Question
-
Has anyone out there been successful at creating a CRM 2011 Online Early Binding Plug-in that works? I'm struggling with one I'm working on and was curious. I haven't seen any documentation anywhere that says you cannot early bind a CRM 2011 online plugin but I also haven't seen any examples of this specifically out there either. I've scoured the web, blogs, sdk, kit and msdn. Nothing has this as an example. If anyone has a template on how to do this I would appreciate it. Then I can compare what I have with where I went wrong.
What I'm trying to do is create an early binding plug-in that copies a specified Opportunity to a New Opportunity along with it's Opportunity Products. Sounds simple enough, right?
The Issue is I get an exception from the plugin stating:
Unexpected exception from plug-in (Execute): XRM.Plugins.CopyOpportunity.CopyOpportunity: System.Security.SecurityException: Request for the permission of type 'System.Security.Permissions.SecurityPermission, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.
This is occuring on the following line of code in my plugin:
using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri, serverConfig.Credentials, serverConfig.DeviceCredentials))
I did generate the device credentials and am using those. Also generated the early binding class with the CrmSvcUtil. That class file is included in my VS project and resolves. The project compiles with no warnings. I also have a server connection class in my project to build the properties and values for the serverConfig parameters being passed into the function above. I did verify that they are getting values.
Any insight would be greatly appreciated.
Thx.
Aaron
AaronSunday, June 5, 2011 3:42 AM
Answers
-
You need to tell the service factory where the proxy types are located. Sadly that's a internal property from a Extensibility class (all CRM-core).
Reflection is your friend ;)
public static void GetPluginObjects(IServiceProvider serviceProvider, out IPluginExecutionContext context, out IOrganizationServiceFactory factory, out IOrganizationService service, out ITracingService tracingService) { // Obtain the execution context from the service provider. context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); // Get a reference to the service factory. factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); factory.GetType().GetProperty("ProxyTypesAssembly").SetValue(factory, typeof(CrmContext).Assembly, null); // Get the plug-in organization service (with enabled proxy types) service = factory.CreateOrganizationService(context.UserId); // Set the tracing service tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); }
- Edited by Guilherme Magalhães Wednesday, January 18, 2012 4:44 PM
- Proposed as answer by Guilherme Magalhães Wednesday, January 18, 2012 4:44 PM
- Marked as answer by DavidJennawayMVP, Moderator Monday, February 13, 2012 11:12 AM
Wednesday, January 18, 2012 4:43 PM
All replies
-
Any specific reason for creating OrganizationServiceProxy? You can use code to get reference to Org Svc
// Get a reference to the Organization service.
IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService_service = factory.CreateOrganizationService(context.UserId);
makeer | myencounterwithcrm.wordpress.com
Sunday, June 5, 2011 4:29 AM -
Hi,
Try it like this:
1. Obtain the execution context
2. Obtain ServiceFactory object
3. Get Crm Service object
// Obtain the execution context from the service provider.
Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext) serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));IOrganizationServiceFactory jj_serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService jj_CrmService = jj_serviceFactory.CreateOrganizationService(context.UserId);
Thank You,
Jehanzeb Javeed,
http://worldofdynamics.blogspot.com
Linked-In Profile |CodePlex Profile
If you find this post helpful then please "Vote as Helpful" and "Mark As Answer".Sunday, June 5, 2011 10:41 AM -
How do I do the early binding line (see below)? Basically, if I use the standard plug-in syntax sugested above, how do I expose the proxy in order to tell it the following?
// This statement is required to enable early-bound type support. _serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
or
// This statement is required to enable early-bound type support. _serviceProxy.EnableProxyTypes();
_serviceProxy is of type OrganizationServiceProxy.
Is there another way using the standard methods for plug-ins to expose the proxy to tell it to enable the proxy type for early binding?
AaronSunday, June 5, 2011 1:06 PM -
You dont have to use EnableProxyTypes if you are using IOrganizationService.
makeer | myencounterwithcrm.wordpress.comSunday, June 5, 2011 6:15 PM -
It won't early bind if I don't include EnableProxyTypes. Since it is CRM Online, the proxy must know about the Strong Entity Types at runtime. It works locally during development with intellisense b/c VS recognizes the name spaces and Entity class types but the Strong Entity Types will not be recognized at runtime unless the proxy is told.
Does IOrganizationService offer an early binding option for CRM Online?
AaronSunday, June 5, 2011 9:38 PM -
Please try this. // Obtain the execution context from the service provider. IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); // Get a reference to the organization service. IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IOrganizationService _service = factory.CreateOrganizationService(context.UserId); _service.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior()); Hope this helps
- Edited by Ramasubramanian Monday, June 6, 2011 6:00 AM modified the code
Monday, June 6, 2011 5:49 AM -
In this case you will not be using OrganizationServiceProxy but IOrganizationService object.
HTH
makeer | myencounterwithcrm.wordpress.comMonday, June 6, 2011 6:00 AM -
In the last line, it states:
_service.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
There is no "ServiceConfiguration" as a member of the IOrganizationService class to select. But there is for OrganizationServiceProxy class.
Any thoughts?
AaronMonday, June 6, 2011 12:15 PM -
I don't see a way for IOrganizationService to allow early binding (Strong Object Types). That's why I'm stuck.
AaronMonday, June 6, 2011 12:17 PM -
Same problem here.
Did someone found a way to support early-bound types in plug-ins and custom workflow activities?
Gael Fraiteur -- SharpCraftersMonday, June 27, 2011 8:47 AM -
- Proposed as answer by yairrose Thursday, July 28, 2011 4:47 AM
Thursday, July 21, 2011 10:44 AM -
yairrose - I read your blog posting regarding this. Great article btw. I noticed that you're pointing at an on-premise instance. Have you gotten that code to work for CRM Online (since proxy is required). I'm trying to acheive early-binding when talking to a CRM Online instance which seems to have slightly different requirements when coding than an on-premise has. Any thoughts? The folks responding to this blog are forgetting that I'm asking how to do early-binding for a CRM Online not on-premise. If you have any insight into this specific scenario, it is much appreciated.
thx.
AaronSunday, July 24, 2011 2:53 PM -
Aaron, you almost gave me an heart attack, I thought i'll have to rewrite whole of my plugin...
BUT I've just finished checking it on crm 2011 online and it worked just fine.I guess i had to check it anyway, but I was just too lazy to start a trial account only for the plugin.
I've also found out that when moving plugin with solution the steps aren't moving with it ?? come on Microsoft if it's already there!
Hope it helps.
Yair.
Monday, July 25, 2011 2:00 PM -
You need to tell the service factory where the proxy types are located. Sadly that's a internal property from a Extensibility class (all CRM-core).
Reflection is your friend ;)
public static void GetPluginObjects(IServiceProvider serviceProvider, out IPluginExecutionContext context, out IOrganizationServiceFactory factory, out IOrganizationService service, out ITracingService tracingService) { // Obtain the execution context from the service provider. context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); // Get a reference to the service factory. factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); factory.GetType().GetProperty("ProxyTypesAssembly").SetValue(factory, typeof(CrmContext).Assembly, null); // Get the plug-in organization service (with enabled proxy types) service = factory.CreateOrganizationService(context.UserId); // Set the tracing service tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); }
- Edited by Guilherme Magalhães Wednesday, January 18, 2012 4:44 PM
- Proposed as answer by Guilherme Magalhães Wednesday, January 18, 2012 4:44 PM
- Marked as answer by DavidJennawayMVP, Moderator Monday, February 13, 2012 11:12 AM
Wednesday, January 18, 2012 4:43 PM -
Will this really work for an online plugin? It has to be sandboxed i.e. partial trust, and you can't use reflection.
Helen
Wednesday, February 29, 2012 7:23 PM -
The proposed solution will not work for Microsoft Dynamics CRM 2011 Online because of sandbox restrictions on reflection ussage. Instead you should use IProxyTypesAssemblyProvider interface which is a standard approach to this situation. If you use developer toolkin from SDK, than you need just change standard Plugin class like this:
internal LocalPluginContext(IServiceProvider serviceProvider) { if (serviceProvider == null) { throw new ArgumentNullException("serviceProvider"); } // Obtain the execution context service from the service provider. this.PluginExecutionContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); // Obtain the tracing service from the service provider. this.TracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService)); // Obtain the Organization Service factory service from the service provider IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory)); IProxyTypesAssemblyProvider proxyTypesProvider = factory as IProxyTypesAssemblyProvider; if (proxyTypesProvider != null) { proxyTypesProvider.ProxyTypesAssembly = typeof(Xrm.XrmServiceContext).Assembly; } // Use the factory to generate the Organization Service. this.OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId); }
Hope this will help. Cheers!- Proposed as answer by Pavel Korsukov Tuesday, August 14, 2012 1:19 AM
Tuesday, August 14, 2012 1:16 AM -
Good response, Pavel!
Helen
Tuesday, August 14, 2012 1:56 AM -
Hi Pavel, really that has been tested and works? I mean, dont get me wrong please, but after beating my head for a while looking a workaround for this issue, I think that should be time for Microsoft to clarify this issues, as far as I reached, CRM Online plugins doesn't support Linq and EarlyBound model.
The main problem is that i couldn't find a way to instantiate OrganisationServiceProxy, main objetc to build Linq queries, using the standard method:
OrganizationServiceProxy serviceProxy = (OrganizationServiceProxy)serviceFactory.CreateOrganizationService(context.UserId);
doesn't work:
System.InvalidCastException: Unable to cast object of type 'Microsoft.Crm.Sandbox.SandboxOrganizationServiceWrapper' to type 'Microsoft.Xrm.Sdk.Client.OrganizationServiceProxy'.
And Microsoft.Crm.Sandbox namespace is not available in the SDK, must be an extension for CRM Online just available in the server.
And the serviceproxy is needed to be able to query crm data using linq.
Maybe i'm missing some point, but taking in account the POOR, almost null, documentation that Microsoft has released around CRM Online limitations... I guess that we have gone further that anyone else. Finally, in summary, you must write specific code for CRM Online, so at least for us this is not an option and we will try to don't push customers up to this Solution.
Comments are welcome.
Cheers,
Israel.
- Edited by Israel.Andres Wednesday, October 10, 2012 9:54 AM
Wednesday, October 10, 2012 9:51 AM -
Israel, this worked for me:
public static void GetPluginObjects(IServiceProvider serviceProvider, out IPluginExecutionContext context, out IOrganizationService service, out ITracingService tracingService,
out XrmServiceContext svcContext)
{
// Obtain the execution context from the service provider.
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));// OrganizationServiceProxy serviceProxy = getOrgProxy();
//service = (IOrganizationService)serviceProxy;// Get a reference to the service factory.
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
// Get the plug-in organization service (with enabled proxy types)
service = factory.CreateOrganizationService(context.UserId);// Cannot use reflection in the Sandbox!!!
//factory.GetType().GetProperty("ProxyTypesAssembly").SetValue(factory, typeof(XrmServiceContext).Assembly, null);
// Set the tracing service
tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// finally, return the service context
svcContext = new XrmServiceContext(service);
}XrnServiceContext if created with the tool and can be used for LINQ queries.
Here is my call to CrmSvcUtil:
CrmSvcUtil.exe /o:c:\Temp\MyEntities.cs /url:https://MyCompany.crm.dynamics.com/XRMServices/2011/Organization.svc /u:MyUser /p:MyPassword /namespace:Xrm /serviceContextName:XrmServiceContext
Hope this helps!
Helen
Helen
Wednesday, October 10, 2012 3:09 PM -
Thanks Helen, we'll try that, sincerely i'm still missing some official documentation about the crmonline limitations, with technical explanations, i'm feeling like a monkey opening a can of beer, trial and error.
Cheers,
Israel.
Thursday, October 11, 2012 4:53 PM -
Israel, this worked for me:
public static void GetPluginObjects(IServiceProvider serviceProvider, out IPluginExecutionContext context, out IOrganizationService service, out ITracingService tracingService,
out XrmServiceContext svcContext)
{
// Obtain the execution context from the service provider.
context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));// OrganizationServiceProxy serviceProxy = getOrgProxy();
//service = (IOrganizationService)serviceProxy;// Get a reference to the service factory.
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
// Get the plug-in organization service (with enabled proxy types)
service = factory.CreateOrganizationService(context.UserId);// Cannot use reflection in the Sandbox!!!
//factory.GetType().GetProperty("ProxyTypesAssembly").SetValue(factory, typeof(XrmServiceContext).Assembly, null);
// Set the tracing service
tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
// finally, return the service context
svcContext = new XrmServiceContext(service);
}XrnServiceContext if created with the tool and can be used for LINQ queries.
Here is my call to CrmSvcUtil:
CrmSvcUtil.exe /o:c:\Temp\MyEntities.cs /url:https://MyCompany.crm.dynamics.com/XRMServices/2011/Organization.svc /u:MyUser /p:MyPassword /namespace:Xrm /serviceContextName:XrmServiceContext
Hope this helps!
Helen
Helen
Hi Helen, using the option that you point me out I'm able to get the reference to the context and build the linq queries, but new problem have come up, apparently when the linq is trying to build the query(CreateQuery()):
Exception: System.TypeLoadException: Inheritance security rules violated while overriding member: 'Microsoft.Crm.Services.Utility.DeviceRegistrationFailedException.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'. Security accessibility of the overriding method must match the security accessibility of the method being overriden.
at System.Reflection.RuntimeAssembly.GetExportedTypes(RuntimeAssembly assembly, ObjectHandleOnStack retTypes)
at System.Reflection.RuntimeAssembly.GetExportedTypes()
at Microsoft.Xrm.Sdk.KnownProxyTypesProvider.LoadKnownTypes(Assembly assembly)
at Microsoft.Xrm.Sdk.KnownProxyTypesProvider.RegisterAssembly(Assembly assembly)
at Microsoft.Xrm.Sdk.AssemblyBasedKnownProxyTypesProvider.GetNameForType(Type type)
at Microsoft.Xrm.Sdk.Client.OrganizationServiceContext.CheckEntitySubclass(Type entityType)
at Microsoft.Xrm.Sdk.Client.OrganizationServiceContext.CreateQuery[TEntity]()
at Trillium.Claremont.CRM.BusinessLayer.Xrm.XrmServiceContext.get_tri_attendanceSet()
at Trillium.Claremont.CRM.BusinessLayer.Xrm.tri_islingtonexport.Export()
at Trillium.Claremont.CRM.BusinessLayer.Xrm.tri_islingtonexport.ProcessExport(Boolean attachAsNote)
at Trillium.Claremont.CRM.Plugins.tri_islingtonexportHandler.Execute(IServiceProvider serviceProvider)I have cheched out that method:
[Serializable]
public sealed class DeviceRegistrationFailedException : Exception....
#region Methods
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
}
#endregionand base method is defined as:
public class Exception : ISerializable, _Exception
{...
public virtual void GetObjectData(SerializationInfo info, StreamingContext context);
which sounds good to me, and these methods are part of the Microsoft Helper that we have integrated in our internal architecture, so dont know how to go forward, any ideas?
Cheers,
Israel.
- Edited by Israel.Andres Monday, October 15, 2012 10:15 AM
Monday, October 15, 2012 10:10 AM -
Hello,
As mentionned in the sdk, if you plan to use early bound entites generated via CrmSvcUtil, do not forget to insert something like :
_serviceProxy = new OrganizationServiceProxy(config.OrganizationUri, config.HomeRealmUri, config.Credentials, config.DeviceCredentials); _serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
Wednesday, January 16, 2013 4:36 PM -
I'm facing this exact issue and this is driving me crazy.
I don't understand Helen's solution and why it would work and I have the same problem as Aaron and Israel (which is basically that the organisationService instanciated online is of hidden type SandboxOrganizationServiceWrapper, cannot be cast to enable proxy type.
Has anyone a real solution to this problem or is it simply not possible ?
Given the amount of code I have to do, I'd prefer to have to have support for binding entities but I don't want to spend days on that problem either...
Tuesday, August 6, 2013 1:18 AM -
hum... ok so I probably found a solution.
Using Pavel's code from above comment, I was still getting invalid cast exception when trying to cast my entity in the plug in to my strongly type object:
Entity importedRecord = localContext.PluginExecutionContext.InputParameters["Target"] as Entity; (importedRecord as Email).Description = "..."; //this fails
However the following works :
Email email = importedRecord.ToEntity<Email>(); email.Description = "working";
Will push further with entity creation etc... but it looks good
Tuesday, August 6, 2013 1:48 AM