Below is the code I am using to create a contact in CRM 2011 online. It's not throwing any error but it also not creating any contact. I have registered the plugin on Post-Operation create event of the e-mail entity. I don't know if I am missing something. Any help would be appreciate.
public class RegistrationPlugin : IPlugin
{
private OrganizationServiceContext oContext;
public void Execute(IServiceProvider serviceProvider)
{
Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
oContext = new OrganizationServiceContext(service);
//service.EnableProxyTypes();
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
try
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName == "email")
{
Guid _contactId;
var contact = new Contact()
{
FirstName = "Mary Kay",
LastName = "Andersen",
Address1_Line1 = "23 Market St.",
Address1_City = "Sammamish",
Address1_StateOrProvince = "MT",
Address1_PostalCode = "99999",
Telephone1 = "12345678",
EMailAddress1 = "marykay#contoso.com",
Id = Guid.NewGuid()
};
_contactId = contact.Id;
oContext.AddObject(contact);
}
}
catch (Exception x)
{
throw new Exception(x.ToString() + "\n" + x.InnerException.ToString());
}
}
}
}
I can see that you're missing one statement which is:
oContext.AddObject(contact);
oContext.SaveChanges(); // <= Saves the changes
It does solves the problem but it is now throwing another error:
Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: Unexpected exception from plug-in (Execute): Microsoft.Crm.Sdk.Samples.RegistrationPlugin: System.Exception: Microsoft.Xrm.Sdk.SaveChangesException: An error occured while processing this request. ---> 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.GetTypeForName(String name, Assembly proxyTypesAssembly)
at..................
It seems to me a problem of rights. Can you suggest what I am missing now?
UPDATE: I solved the problem by adding OwnerID = new EntityReference("systemuser", context.UserId)
hmm, I think you don't need to complete the ID field, because when you will create it, the CRM will send you the ID.
Don't know if it could help you, cause I don't create a contact but an incident. But I think the process is the same. So I let you look.
private Guid createCase(IOrganizationService CrmService, Entity email)
{
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
tracingService.Trace("Just to tracing my plugin");
/* CREATE AN ENTITY: incident here, but could be contact, account, ... */
Entity incident = new Entity("incident");
incident["title"] = email.Attributes["subject"].ToString();
incident["caseorigincode"] = new OptionSetValue(2);
EntityCollection ec = email.Attributes["from"] as EntityCollection;
Entity from = ec.Entities.FirstOrDefault();
incident["customerid"] = (EntityReference)from.Attributes["partyid"];
/* END */
tracingService.Trace("tracing 2.");
/* HERE YOU CREATE THE RECORD IN THE CRM */
Guid caseid = CrmService.Create(incident);
/* END */
tracingService.Trace("tracing 3. ID: "+ caseid.ToString());
return caseid;
}
Related
I need to connect and retrieve records in CRM Online through CRM 365 plugin. I have tried simplified connection using xrm.tooling.dll but unfortunately it says Could not load file or assembly 'microsoft.xrm.tooling.connectorand when i used ClientCredential the error says Metadata contain refereces that cannot be resolved.
Strangely, i tried both method with console applcation and it's work prefectly. Just wanna knows what i miss in this case ? Do i need special requirement when i want to connect to CRM through plugin ? Please anybody share your knowledge.
EDIT
This just a sample code to get account name from CRM Online and display it using 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);
}
You should be able to connect to another CRM instance without using any assemblies that are outside Online Sandbox (so other than Microsoft.Xrm.Sdk and related). Simply use the sample from SDK from "SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs". Simplified version for connecting to Office365 looks like that:
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();
}
}
You can simplify it further by removing part with DiscoveryService and directly calling:
https://orgname.api.crm.dynamics.com/XRMServices/2011/Organization.svc
This should work on Sandboxed plugins as it uses only Sdk assemblies.
You already have your connection to CRM using the IOrganizationService that you've defined on the third line of your plugin. Unless you need to connect to another CRM instance in a different org, there is no login needed or required.
Basically just delete the 4 lines above your try, and you should be good.
Edit:
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);
}
}
You do not need any additional libraries like Microsoft.Xrm.Tooling.Connector or others from SDK to consume CRM web services. Standard .NET mechanism related to SOAP / REST protocols will be enough (but of course this method may be little more difficult).
EDIT: I've made some additional investigation and it occurs that configuring auto-generated OrganizationServiceClient for Office365 authentication without using SDK libraries may be real pain in the ass. I'm not telling it is not possible however it is not documented by Microsoft. To add more details OAuth authentication is not supported by Visual Studio generated proxy classes.
Because of that - my second recommendation is to use facade web service communicating with CRM OnLine. You may host this web service on Windows Azure or any other cloud/hosting place in the internet. From your CRM 365 Plugin you may consume your custom web service methods and communicate with your CRM Online instance using this service. I suppose it will be much better approach that trying to run undocumented methods of connecting to CRM Online.**
You should be able to connect to another CRM instance without using any assemblies that are outside Online Sandbox (so other than Microsoft.Xrm.Sdk and related).
For example simply use the sample from SDK from SDK\SampleCode\CS\GeneralProgramming\Authentication\AuthenticateWithNoHelp\AuthenticateWithNoHelp.cs.
I have registered a plugin for update message of some entity (in post-operation) via CRM tool in Visual Studio and also registered post-image for that plugin like below:
and here is my code :
protected void ExecutePostOpportunityUpdate(LocalPluginContext
localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
// TODO: Implement your custom Plug-in business logic.
IPluginExecutionContext context = localContext.PluginExecutionContext;
Entity postImage = (Entity)context.PostEntityImages["PostImage"];
....
}
But it throws an error and says that there is no key in PostEntityImages at all. I debugged the plugin and saw that there is no key in that at all.
Would you help me please?
Well looking at your code you have to retrieve the actual entity of Opportunity: Try this
try
{
Entity postOpportunityService = (Entity)context.PostEntityImages["PostImage"];
// Opportunity service's parent opportunity lookup reference
EntityReference opportunityReference = (EntityReference)postOpportunityService.Attributes["mpc_opportunityid"];
// Columns to be retrieved for opportunity (aka. columns to be edited)
ColumnSet opportunityColumnSet = new ColumnSet(new string[] { "estimatedvalue", "mpc_estoneoffinvoicing", "mpc_estinvoicingperyear" });
// Retrieve actual opportunity entity
Entity opportunity = service.Retrieve(opportunityReference.LogicalName, opportunityReference.Id, opportunityColumnSet);
}
catch (FaultException<OrganizationServiceFault> ex) { tracingService.Trace("FaultException", ex.ToString()); }
I am trying to populate a field in the system user entity whenever a user creates an account. I keep getting errors when trying to retrieve the system user entity so that I can populate its attributes. My code is as follows:
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingservice = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.InitiatingUserId);
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
try
{
//Get entity that fired plugin
Entity entMain = (Entity)context.InputParameters["Target"];
//Make a String for the last activity entity
String strLastEntity = "";
//Make the entity for the user entity
Entity entUser = (Entity)service.Retrieve("systemuser", context.InitiatingUserId, new ColumnSet(new String[] { "new_lastactivityentity" }));
//Get the entity type that fired the plugin and set it to the right field for the user entity
if (entMain.LogicalName.Equals("account"))
{
strLastEntity = entMain.LogicalName;
entUser["new_lastactivityentity"] = strLastEntity;
}
}
catch (Exception ex)
{
tracingservice.Trace("FollowupPlugin: {0}", ex.ToString());
throw;
}
}
}
The error is:
Could not load file or assembly 'PluginRegistration, Version=2.1.0.1, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
Can someone explain how to get the system user so I can update its attributes?
It is because you have an assembly reference that isn't installed on the server, in particular that is PluginRegistration.
You could place that dll in the GAC on the server, however this won't work for CRM Online (or in a Sandbox registration I believe).
Is PluginRegistration a reference to the Microsoft assembly used in the plugin registration tool? Generally speaking you don't need a reference to that in your project, so you could try removing the reference.
everyone,
I'm having a problem that does not appear in the output parameter list on the right side under "Look for" underneath "Local Values", I do not understand the problem or reason for not appear, since in terms of input parameters's okay.
protected override void Execute(CodeActivityContext executionContext)
{
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
//Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
tracingService.Trace("Creating Account");
Account entity = new Account();
entity.Name = AccountName.Get<string>(executionContext);
Guid entityId = service.Create(entity);
string a = entity.Name;
AccountNameTest.Set(executionContext, a);
tracingService.Trace("Account created with Id {0}", entityId.ToString());
tracingService.Trace("Create a task for the account");
Task newTask = new Task();
newTask.Subject = TaskSubject.Get<string>(executionContext);
newTask.RegardingObjectId = new EntityReference(Account.EntityLogicalName, entityId);
Guid taskId = service.Create(newTask);
tracingService.Trace("Task has been created");
tracingService.Trace("Retrieve the task using QueryByAttribute");
QueryByAttribute query = new QueryByAttribute();
query.Attributes.AddRange(new string[] { "regardingobjectid" });
query.ColumnSet = new ColumnSet(new string[] { "subject" });
query.EntityName = Task.EntityLogicalName;
query.Values.AddRange(new object[] { entityId });
tracingService.Trace("Executing the Query for entity {0}", query.EntityName);
//Execute using a request to test the OOB (XRM) message contracts
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
Collection<Entity> entityList = ((RetrieveMultipleResponse)service.Execute(request)).EntityCollection.Entities;
//Execute a request from the CRM message assembly
tracingService.Trace("Executing a WhoAmIRequest");
service.Execute(new WhoAmIRequest());
if (1 != entityList.Count)
{
tracingService.Trace("The entity list was too long");
throw new InvalidPluginExecutionException("Query did not execute correctly");
}
else
{
tracingService.Trace("Casting the Task from RetrieveMultiple to strong type");
Task retrievedTask = (Task)entityList[0];
if (retrievedTask.ActivityId != taskId)
{
throw new InvalidPluginExecutionException("Incorrect task was retrieved");
}
tracingService.Trace("Retrieving the entity from IOrganizationService");
//Retrieve the task using Retrieve
retrievedTask = (Task)service.Retrieve(Task.EntityLogicalName, retrievedTask.Id, new ColumnSet("subject"));
if (!string.Equals(newTask.Subject, retrievedTask.Subject, StringComparison.Ordinal))
{
throw new InvalidPluginExecutionException("Task's subject did not get retrieved correctly");
}
//Update the task
retrievedTask.Subject = UpdatedTaskSubject.Get<string>(executionContext);
service.Update(retrievedTask);
}
}
//
[Input("Name conta")]
[Default("testv01")]
public InArgument<string> AccountName { get; set; }
[Input("Task")]
[Default("testv01")]
public InArgument<string> TaskSubject { get; set; }
[Input("Update task")]
[Default("testUPDATED:v01}")]
public InArgument<string> UpdatedTaskSubject { get; set; }
[Output("Account ID Guid")]
[Default("testUPDATED:v01")]
public OutArgument<string> AccountNameTest { get; set; }
Ok, problem solved, just restart IIS to assume the fields, or through version change. The problem was the update of the plugin, this also happens with workflows. According to CRM 4.0 i realized this situation does not happen in CRM 4.0.
Even though this Question is already answered I wanted to share two Cases where this solution didn't work (even in a recent Version of CRM):
Case 1
Having choosen Input-Parameter-Names that contained german Umlauts (äöüß).
IIS-restart did not help.
Choosing Names without Umlauts solved the Problem for me.
Case 2
We recently also had a case where a normal In-Argument did not show up, even after restarting the entire Maschine CRM was running on. The Solution was not to obvious:
Open PluginRegistrationTool from SDK
Choose the Assembly that contains your CWA
Choose your CWA
Hit the Save-Button in the Properties-Tab of your CWA
I am trying to update the telephone number on all associated contacts of an account entity. the following is the code that i have used,
public class Plugin:IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
Entity entity;
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName != "account") { return; }
}
else
{
return;
}
try
{
string telephoneNum = string.Empty;
IOrganizationServiceFactory serviceFactory =(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service =serviceFactory.CreateOrganizationService(context.UserId);
var id = (Guid)context.OutputParameters["id"];
telephoneNum = entity.GetAttributeValue<string>("telephone1");
UpdateContact(service, id,telephoneNum);
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException(
"An error occurred in the plug-in.", ex);
}
}
private static void UpdateContact(IOrganizationService service, Guid id,string telephoneNUm)
{
using (var crm = new XrmServiceContext(service))
{
var res = from c in crm.CreateQuery("contact")
where c["parentcustomerid"].Equals(id)
select c;
foreach (var c in res)
{
Entity e = (Entity)c;
e["telephone1"] = telephoneNUm;
crm.UpdateObject(e);
}
crm.SaveChanges();
}
}
}
I register the plugin on update, and primary entity "account" but whenever i try to save the account form after change of number in the telephone field i see an error pop up. Am i missing something? Thank you all!
Just a hunch..but I think you are getting the Id in the wrong way..try getting it by:
Guid Id = context.PrimaryEntityId
But as Pedro suggested..you need to see what is the exact error or try to debug the plugin using attach to process..