I am trying to run a sample plugin for MS CRM. but I am getting following error:
An error occurred. Contact a system administrator or refer to the
Microsoft Dynamics CRM SDK troubleshooting guide.
here is the code:
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("account") &&
context.InputParameters["account"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity entity = (Entity)context.InputParameters["account"];
try
{
//check if the account number exist
if (entity.Attributes.Contains("account number") == false)
{
//create a task
Entity task = new Entity("task");
task["subject"] = "Account number is missing";
task["regardingobjectid"] = new EntityReference("account", new Guid(context.OutputParameters["id"].ToString()));
//adding attribute using the add function
// task["description"] = "Account number is missng for the following account. Please enter the account number";
task.Attributes.Add("description", "Account number is missng for the following account. Please enter the account number");
// Obtain the organization service reference.
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Create the task in Microsoft Dynamics CRM.
service.Create(task);
}
}
catch (FaultException ex)
{
throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
}
}
}
}//end class
This is an example code, and I have verified that all the entities and fields which are utilized by this plugin are defined and are at there places. but I am continuously getting this Business Error.
I found the Solution: Instead of explicitly mentioning "account", we have to use:
Entity entity = (Entity)context.InputParameters["Target"];
The second reason for error was the restriction inside CRM which was not allowing creation of new accounts. Works fine when used to create new "contact."
Thanks a lot everyone for help.
Please check it like this
Entity entity = context.InputParameters["account"] as Entity;
some times that doesn't work properly.
Related
I am using a pre-operation retrieve multiple plugin to add a condition to account subgrid lookups. This works fine, however it applies to all queries on account entities. I want it to only apply when the user accesses the lookup within one subgrid on one form. Is there any way to retrieve the lookup which fires the query? Alternatively is the any way to achieve what I want to do by other means? The purpose of this is to filter the accounts which can be added to the subgrid.
Here is my code:
public class FilterAversedSuppliers : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
// Obtain the execution context from the service provider.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Query") &&
context.InputParameters["Query"] is QueryExpression)
{
try
{
QueryExpression objQueryExpression = (QueryExpression)context.InputParameters["Query"];
ConditionExpression condition = new ConditionExpression()
{
AttributeName = "customertypecode",
Operator = ConditionOperator.Equal,
Values = { 4 }
};
objQueryExpression.Criteria.AddCondition(condition);
tracingService.Trace("Custom Filter Added");
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in the FollowupPlugin plug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("FollowupPlugin: {0}", ex.ToString());
throw;
}
}
}
}
On the criteria for the lookup view, add something like “Name” equals “FilterMe”.
Now in your plugin, inspect the incoming fetchxml query. If it contains your special criteria, you know to apply your special filtering. Don’t forget to remove the special criteria from the query in your code.
Now all other queries should not trigger your special filter.
I am using this tutorial in order to connect a xamarin.forms app with easy tables. I cannot add data to the database in Azure as i get
System.InvalidOperationException
The error message is the following
An insert operation on the item is already in the queue.
The exception happends in the following line of code.
await usersTable.InsertAsync(data);
In order to add a user
var user = new User { Username = "username", Password = "password" };
bool x = await AddUser(user);
AddUser
public async Task<bool> AddUser(User user)
{
try
{
await usersTable.InsertAsync(user);
await SyncUsers();
return true;
}
catch (Exception x)
{
await new MessageDialog(x.Message.ToString()).ShowAsync();
return false;
}
}
SyncUsers()
public async Task SyncUsers()
{
await usersTable.PullAsync("users", usersTable.CreateQuery());
await client.SyncContext.PushAsync();
}
where
IMobileServiceSyncTable<User> usersTable;
MobileServiceClient client = new MobileServiceClient("url");
Initialize
var path = Path.Combine(MobileServiceClient.DefaultDatabasePath, "DBNAME.db");
var store = new MobileServiceSQLiteStore(path);
store.DefineTable<User>();
await client.SyncContext.InitializeAsync(store, new MobileServiceSyncHandler());
usersTable = client.GetSyncTable<User>();
Please check your table. You probably have added the item already. Also, I would suggest that you don't set the Id property for your entity, because you might be inserting a same ID that's already existing in your table. It's probably the reason why the exception is appearing.
Hope it helps!
Some debugging you can do:
1) Turn on diagnostic logging in the backend and debug the backend: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter8/developing/#debugging-your-cloud-mobile-backend
2) Add a logging delegating handler in your MobileServiceClient setup: https://adrianhall.github.io/develop-mobile-apps-with-csharp-and-azure/chapter3/server/#turning-on-diagnostic-logs
The MobileServicePushFailedException contains an inner exception that contains the actual error. Normally, it is one of the 409/412 HTTP errors, which indicates a conflict. However, it can also be a 404 (which means there is a mismatch between what your client is asking for and the table name in Easy Tables) or 500 (which means the server crashed, in which case the server-side diagnostic logs indicate why).
Easy Tables is just a Node.js service underneath the covers.
I create custom error logger in CRM 2013 have functionality to save error information into CRM entity. I debug my code and find that my code works well. But the problem is when CRM rollback the transaction, the log entity also disappear. I want to know is it possible to create entity on catch block and still throw that error?
public void Execute(IServiceProvider serviceProvider)
{
try
{
...
}
catch (Exception ex)
{
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.
GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(Guid.Empty);
var log = new Log
{
Message = ex.Message
};
service.Create(log);
throw;
}
}
I found the other way to solve this issue. We can create new service to create new transaction outside the transaction being failed. Here some snippet if you want to do the same:
try
{
...
}
catch (Exception ex)
{
var HttpCurrentContext = HttpContext.Current;
var UrlBase = HttpCurrentContext.Request.Url.Host;
string httpUrl = #"http://";
if (HttpCurrentContext.Request.IsLocal)
{
UrlBase += ":" + HttpCurrentContext.Request.Url.Port;
}
if (!UrlBase.Contains(httpUrl))
{
UrlBase = httpUrl + UrlBase;
}
var UriBase = UriBuilder(UrlBase.ToLowerInvariant().Trim() + "/xrmservices/2011/organization.svc").Uri;
IServiceConfiguration<IOrganizationService> orgConfigInfo =
ServiceConfigurationFactory.CreateConfiguration<IOrganizationService>(UriBase);
var creds = new ClientCredentials();
using (_serviceProxy = new OrganizationServiceProxy(orgConfigInfo, creds))
{
// This statement is required to enable early-bound type support.
_serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());
_service = (IOrganizationService)_serviceProxy;
var log = new Log
{
Message = ex.Message
};
_service.Create(NewLog);
}
throw;
}
Essentially, no. You cannot prevent that an exception rolls back the transaction. See a similar question on StackOverflow.
A common approach is to create a separate logging service that can store logs outside of the database transaction.
B.t.w. Dynamics CRM 2015 spring release introduces the capability to store logs regardless if your plugin is participating in a database transaction.
I've written a plugin with the following configuration:
I'm simply trying to set one datetime field to equal another datetime field:
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity entity = (Entity)context.InputParameters["Target"];
try
{
if (entity.LogicalName == "list" && entity.Attributes["gbs_lastusedonoriginal"] != null)
{
entity.Attributes["lastusedon"] = entity.Attributes["gbs_lastusedonoriginal"];
service.Update(entity);
}
}
catch (FaultException ex)
{
throw new InvalidPluginExecutionException("An error occured in the plug-in.", ex);
}
}
The exception I get is:
Unhandled Exception:
System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault,
Microsoft.Xrm.Sdk, Version=6.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35]]: An error occured in the
plug-in.Detail:
-2147220891
OperationStatus
0
SubErrorCode
-2146233088
An error occured in the plug-in.
2015-01-15T05:34:00.1772929Z
[PreValidationMarketingList.Plugins:
PreValidationMarketingList.Plugins.PreValidateMarketingListCreate]
[5454a088-749c-e411-b3df-6c3be5a83130: PreValidateMarketingListCreate]
Entered
PreValidationMarketingList.Plugins.PreValidateMarketingListCreate.Execute(),
Correlation Id: 6d3ed105-f9c4-4006-9c80-08abd97c0140, Initiating User:
5e1b0493-d07b-e411-b592-f0921c199288
PreValidationMarketingList.Plugins.PreValidateMarketingListCreate is
firing for Entity: list, Message: Create, Correlation Id:
6d3ed105-f9c4-4006-9c80-08abd97c0140, Initiating User:
5e1b0493-d07b-e411-b592-f0921c199288 Exiting
PreValidationMarketingList.Plugins.PreValidateMarketingListCreate.Execute(),
Correlation Id: 6d3ed105-f9c4-4006-9c80-08abd97c0140, Initiating User:
5e1b0493-d07b-e411-b592-f0921c199288
What am I doing wrong?In crm 2013 how do I set one field to equal another field if both of them are datetimes?
You shouldn't be calling Update in this plugin because you haven't created and saved the record you are trying to update.
First, move this to pre-operation, not pre-validation. It's a nit but pre-op is really the appropriate place since setting lastusedon is not required for validation on Create of list.
I've reworked your code to do some additional checks:
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity entity = (Entity)context.InputParameters["Target"];
try
{
if (entity.LogicalName == "list" && entity.Attributes.Contains("gbs_lastusedonoriginal") && entity["gbs_lastusedonoriginal"] != null)
{
if (entity.Attributes.Contains("lastusedon") )
entity.Attributes["lastusedon"] = entity.Attributes["gbs_lastusedonoriginal"];
else entity.Attributes.Add("lastusedon", entity.Attributes["gbs_lastusedonoriginal"];
}
}
catch (FaultException ex)
{
throw new InvalidPluginExecutionException("An error occured in the plug-in.", ex);
}
}
Check this link on MSDN. In the Pre-Event, the record is not yet saved in the SQL database. You can modify the Entity object from the InputParameters. After the pre-event plugin the record will be created with your modified attributes.
The main difference between Pre-validation and Pre-operation is that the Pre-operation stage is executed within the database transaction while Pre-validation not. See MSDN for more information.
I am working on a CRM Dynamics Plugin. There is a field on custom entity named "email". I want to make sure that for two entity records email addresses should be unique. For that purpose I have written following code:
public class Class1 : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
// Get a reference to the organization service.
IOrganizationServiceFactory factory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
//</snippetAccountNumberPlugin2>
// Verify that the target entity represents an account.
// If not, this plug-in was not registered correctly.
if (context.MessageName.ToUpper() == "CREATE")
{
if (entity.LogicalName == "new_assignment1entity")
{
try
{
QueryExpression query = new QueryExpression("new_assignment1entity");
query.ColumnSet.AddColumns("new_email");
EntityCollection result1 = service.RetrieveMultiple(query);
foreach (var a in result1.Entities)
{
int size = result1.Entities.Count;
if (a.Attributes["new_email"].ToString().Equals(entity["new_email"]))
throw new InvalidPluginExecutionException("Duplicate Email found!");
}
}
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
{
//You can handle an exception here or pass it back to the calling method.
throw new InvalidPluginExecutionException("Some problem occurred while Querying Records!");
}
}
}
else if (context.MessageName.ToUpper() == "UPDATE")
{
if (entity.LogicalName == "new_assignment1entity")
{
try
{
QueryExpression query = new QueryExpression("new_assignment1entity");
query.ColumnSet.AddColumns("new_email");
EntityCollection result1 = service.RetrieveMultiple(query);
foreach (var a in result1.Entities)
{
int size = result1.Entities.Count;
if (a.Attributes["new_email"].ToString().Equals(entity["new_email"]))
throw new InvalidPluginExecutionException("Duplicate Email found!");
}
}
catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
{
//You can handle an exception here or pass it back to the calling method.
throw new InvalidPluginExecutionException("Some problem occurred while Querying Records!");
}
}
}
}
}
}
When User creates a new entity record with duplicate email address this code works and shows a dialog box printing error message. But when User edit an existing record (update and existing record) and makes the email address duplicate then this code does not work and updated record with duplicated email address saved.
I am guessing that Context message with UPDATE else part is not working.
Please help me out.
It's not really worth trying to debug this as unfortunately you are going about this in a horribly inefficient way. (Though the most likely cause is the way you are querying being subject to a "feature" of CRM which means you are not querying all the records you think you are).
In short, your code says:
Get me ALL(*) instances of the new_assignment1entity entity
Look at each record until I find one with an email address that matches (case-sensitive) the value just provided in the update
Throw an exception when you encounter the first exact match (otherwise continue with the transaction)
Mains points of note:
QueryExpression will only return the maximum first 5000 records in CRM
You should be filtering your query to only return new_assignment1entity records where the new_email attribute matches the provided value
String.Equals(string) is case-sensitive so to truly check for a duplicate, you should convert the case of each value
Your size variable serves no purpose
Your code will throw an exception if the new/updated record has no value for new_email. You should check that the attribute exists before attempting to access it
I resolved this issue. The problem why only Create execution flow was running and not Update is that I had only registered the plugin for create message step. To overcome this issue, I added a new step in same plugin and registered it with update message as show in following screenshot:
And it worked like charm.
Apart from this, #GregOwens mentioned very helpful points.These should follow as best practices in CRM Development.