Dynamics 365 Plugin for lookup values - c#

Error: 0x80040203 Invalid Argument
I'm new to Dynamics. In preparation for getting lookup values from external data source into Dynamics via a plugin, I wanted to test first with hard coded values with this code. But after I registered the assembly, data provider and data source, I created a virtual entity in dynamics which I linked up to a field (lookup type) on a form. After publishing, clicking on the field throws error - Invalid Argument
using System;
using Microsoft.Xrm.Sdk;
namespace Hardcoded.Names.Plugin
{
public class NamesLookupPlugin : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
serviceFactory.CreateOrganizationService(context.UserId);
var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
try
{
var results = new EntityCollection();
var itemOne = new Entity
{
["ID"] = Guid.NewGuid(),
["Name"] = "First Item"
};
var itemTwo = new Entity()
{
["ID"] = Guid.NewGuid(),
["Name"] = "Second Item"
};
results.Entities.Add(itemOne);
results.Entities.Add(itemTwo);
context.OutputParameters["BusinessEntityCollection"] = results;
}
catch (Exception e)
{
tracingService.Trace($"{e.Message} {e.StackTrace}");
if (e.InnerException != null)
tracingService.Trace($"{e.InnerException.Message} {e.InnerException.StackTrace}");
throw new InvalidPluginExecutionException(e.Message);
}
}
}
}
I expect to see "First Item" and "Second Item" selectable in the lookup field.

You’re hooking on RetrieveMultiple message in your plug-in. There is also Retrieve message (get single record by EntityReference) - you need to hook on that message as well for your entity.

Related

Attempt by method x to access method y failed

I have write a code base on other code.
It is a plugin for Dynamic CRM 2011.
Anyways, I wanna replace this plugin with existing Plugin.
It is almost a mirror of another .dll Plugin.
Anyways, In customization of CRM, I have disabled All steps of previous Plugin and want to insert new Plugin via Plugin Registration.
I build my class library via VS, VS makes a .dll file in /bin/Debug folder of project.
I select insert that .dll as Register new assembly.
I chose Sandbox as Isolation mode.
And then database as location ( Not Disk or GAC ).
It successfully updated my selected Plugin.
After that, I insert my steps( Just like the previous Plugin I wanna replace with ).
But in one the create methods, I get this 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): OrderReceiptStepPlugin: System.MethodAccessException:
Attempt by method 'Microsoft.Xrm.Sdk.Entity.ToEntity<System.__Canon>()' to access method 'StepType..ctor()' failed.Detail:
<OrganizationServiceFault xmlns:i="www.w3.org/.../XMLSchema-instance"
xmlns="schemas.microsoft.com/.../Contracts">
<ErrorCode>-2147220956</ErrorCode>
<ErrorDetails xmlns:d2p1="schemas.datacontract.org/.../System.Collections.Generic" />
<Message>Unexpected exception from plug-in (Execute): OrderReceiptStepPlugin: System.MethodAccessException:
Attempt by method 'Microsoft.Xrm.Sdk.Entity.ToEntity<System.__Canon>()' to access method 'StepType..ctor()' failed.</Message>
<Timestamp>xxxxxxxxxx.4628797Z</Timestamp>
<InnerFault i:nil="true" />
<TraceText>
[OrderReceiptStep: OrderReceiptStepPlugin]
[xxxxxx-xxxx-xxxx11-xxx-xxxxxxxxxxxx: OrderReceiptStepPlugin: Create of bmsd_orderreceiptstep]
Entered .Execute(), Correlation Id: 47c5ddcb-9290-4945-9ac0-fd88925480b1, Initiating User: 5b6b27be-ca0f-e811-bebe-000c2964dd77
is firing for Entity: bmsd_orderreceiptstep, Message: Create, Correlation Id: 47c5ddcb-9290-4945-9ac0-fd88925480b1, Initiating User: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
Exiting .Execute(), Correlation Id: xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, Initiating User: xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxx
</TraceText>
</OrganizationServiceFault>
I googled about MethodAccessException Find out that this method occurs because of .Net version 4 and later,
And some code you can add in your Assebmly.cs to avoid this exception, according to this thread.
But in my case no success.
I added the code below to my assembly.cs but no success :
[assembly: SecurityTransparent()]
[assembly: AllowPartiallyTrustedCallersAttribute]
Here is the code that cause the error, It is in pre-Create of custom entity :
private void OrderReceiptStepPreCreateEventHandler(LocalPluginContext context)
{
SalesOrderReceiptStepRepository salesOrderReceiptStepRepository = new SalesOrderReceiptStepRepository(context);
SalesOrderReceiptStep salesOrderReceiptStep = salesOrderReceiptStepRepository.CreateInstance();
salesOrderReceiptStep.TotalAmountWithoutTax = new Money(salesOrderReceiptStep.TotalAmountWithoutTax.Value + salesOrderReceiptStep.FreightAmount.Value);
salesOrderReceiptStep.TotalAmountWithoutTax = new Money(salesOrderReceiptStep.TotalAmountWithoutTax.Value - salesOrderReceiptStep.DiscountAmount.Value);
switch (salesOrderReceiptStep.ReceiptStepType)
{
case ReceiptStepType.TimeOriented:
case ReceiptStepType.PrePayment:
case ReceiptStepType.Others:
salesOrderReceiptStep.TotalAmountWithoutTax = new Money(salesOrderReceiptStep.TotalDetailAmount.Value + salesOrderReceiptStep.FreightAmount.Value - salesOrderReceiptStep.DiscountAmount.Value);
salesOrderReceiptStep.TotalAmount = new Money(salesOrderReceiptStep.TotalAmountWithoutTax.Value + salesOrderReceiptStep.TotalTax.Value);
break;
}
OrderReceiptStepCalculationPlugin orderReceiptStepCalculationPlugin = new OrderReceiptStepCalculationPlugin();
orderReceiptStepCalculationPlugin.CreateORderReceiptStep(context, salesOrderReceiptStep);
if (salesOrderReceiptStep.Contains("bmsd_totallineitemamount") && salesOrderReceiptStep.Contains("bmsd_orderid"))
{
EntityReference attributeValue = salesOrderReceiptStep.GetAttributeValue<EntityReference>("bmsd_orderid");
if (attributeValue != null)
{
SalesOrderAdapter salesOrderAdapter = new SalesOrderAdapter();
OrganizationServiceContext context2 = new OrganizationServiceContext(context.OrganizationService);
Entity ordersById = salesOrderAdapter.GetOrdersById(context2, attributeValue.Id);
if (ordersById != null)
{
CalculationHelper calculationHelper = new CalculationHelper();
Entity entity = calculationHelper.CalculateOrdersAndReturnEntity(context, ordersById, ordersById);
entity.Attributes["statuscode"] = null;
entity.Attributes["statecode"] = null;
context.OrganizationService.Update(entity);
}
}
}
if (salesOrderReceiptStep.Contains("bmsd_invoiceid") || salesOrderReceiptStep.Contains("statuscode") || salesOrderReceiptStep.Contains("statecode") || salesOrderReceiptStep.Contains("bmsd_totallineitemamount"))
{
EntityReference attributeValue2 = salesOrderReceiptStep.GetAttributeValue<EntityReference>("bmsd_invoiceid");
if (attributeValue2 != null)
{
OrganizationServiceContext context2 = new OrganizationServiceContext(context.OrganizationService);
OrderReceiptItemAdapter orderReceiptItemAdapter = new OrderReceiptItemAdapter();
Entity invoiceById = orderReceiptItemAdapter.GetInvoiceById(context2, attributeValue2.Id);
if (invoiceById != null)
{
CalculationHelper calculationHelper = new CalculationHelper();
Entity entity2 = calculationHelper.CalculateInvoiceAndReturnEntity(context, invoiceById, invoiceById);
entity2.Attributes["statuscode"] = null;
entity2.Attributes["statecode"] = null;
context.OrganizationService.Update(entity2);
}
}
}
}
I know this is not a syntax or logical error in development ( Cause the mirror is working correctly).
What other reasons can make this error?
Also here is the Class that Exception throw from that, It also contains the Execute medthod :
public void Execute(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
throw new ArgumentNullException("serviceProvider");
}
LocalPluginContext localcontext = new LocalPluginContext(serviceProvider);
localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Entered {0}.Execute()", new object[1]
{
ChildClassName
}));
try
{
Action<LocalPluginContext> action = (from a in RegisteredEvents
where a.Item1 == localcontext.PluginExecutionContext.Stage && a.Item2 == localcontext.PluginExecutionContext.MessageName &&
(string.IsNullOrWhiteSpace(a.Item3) || a.Item3 == localcontext.PluginExecutionContext.PrimaryEntityName)
select a.Item4).FirstOrDefault();
if (action != null)
{
localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "{0} is firing for Entity: {1}, Message: {2}", new object[3]
{
ChildClassName,
localcontext.PluginExecutionContext.PrimaryEntityName,
localcontext.PluginExecutionContext.MessageName
}));
action(localcontext);
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Exception: {0}", new object[1]
{
ex.ToString()
}));
throw;
}
finally
{
localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Exiting {0}.Execute()", new object[1]
{
ChildClassName
}));
}
}

Dynamics 365 (On-Prem): Share record with multiple teams - C#

I have a situation where I will need to share records with all teams. All my traces show that all the team names and record are what they should be (I took out the traces in the code to save space). However, the record isn't sharing upon testing. Do I have this written correctly? I guess my logic was to loop through all teams and share the record. Pulling my hair out with the one. The following is my wf assembly code:
using Microsoft.Xrm.Sdk.Workflow;
using System;
using System.Activities;
using System.Diagnostics;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
namespace workfow_ShareWithAllTeams
{
public class workfow_ShareWithAllTeams : CodeActivity
{
protected override void Execute(CodeActivityContext executionContext)
{
ITracingService tracer = executionContext.GetExtension<ITracingService>();
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
try
{
Entity entity = (Entity) context.InputParameters["Target"];
//TODO: Do stuff
QueryExpression qe = new QueryExpression();
qe.EntityName = "team";
qe.ColumnSet = new ColumnSet();
qe.ColumnSet.Columns.Add("teamid");
qe.ColumnSet.Columns.Add("name");
var teams = service.RetrieveMultiple(qe);
Guid Id = context.PrimaryEntityId;
QueryExpression query = new QueryExpression("item");
query.ColumnSet = new ColumnSet();
query.ColumnSet.Columns.Add("itemid");
query.ColumnSet.Columns.Add("name");
query.Criteria.AddCondition(new ConditionExpression("itemid", ConditionOperator.Equal, Id));
var recordToShare = service.RetrieveMultiple(query);
foreach (Entity team in teams.Entities) //looping through all teams to share
{
foreach (Entity record in recordToShare.Entities)//only one record in entity collection
{
GrantAccessRequest grant = new GrantAccessRequest();
grant.Target = new EntityReference(entity.LogicalName, entity.Id);
PrincipalAccess principal = new PrincipalAccess();
principal.Principal = new EntityReference(team.LogicalName, team.Id);
principal.AccessMask = AccessRights.ReadAccess | AccessRights.AppendAccess |
AccessRights.WriteAccess | AccessRights.AppendToAccess |
AccessRights.ShareAccess | AccessRights.AssignAccess;
grant.PrincipalAccess = principal;
}
}
}
catch (Exception e)
{
throw new InvalidPluginExecutionException(e.Message);
}
}
}
}
Everything is perfect, except the below line is missing:
service.Execute(grant);
Well, I think I answered my own question. Took me hours to figure I was missing the following 1 line of vital code:
GrantAccessResponse granted = (GrantAccessResponse)serice.Execute(grant);
Adding this worked.

How to Insert data using lookup CRM 365 through Plugin C#

i have a lookup "new_lookuptransactionheader" in my entity "new_trialxrmservicetoolkit". This lookup linked from "new_transactionheader" entity. How can i insert data using c# crm plugin?
this mycode:
public void InsertDataUsingLookup(XrmServiceContext xrm, Entity entitiy, ITracingService tracer)
{
new_trialxrmservicetoolkit trial = new new_trialxrmservicetoolkit();
trial.new_name = "testplugin";
trial.new_LookupTransactionHeader = null; //this is i don't know how to get value from new_LookupTransactionHeader
trial.new_Notes = "this is test plugin using c#";
xrm.AddObject(trial);
xrm.SaveChanges();
}
I updated mycode and this solve:
public void InsertDataUsingLookup(XrmServiceContext xrm, Entity entitiy, ITracingService tracer)
{
new_trialxrmservicetoolkit trial = new new_trialxrmservicetoolkit();
trial.new_name = "testplugin";
trial.new_LookupTransactionHeader = new EntityReference("new_transactionheader", Guid.Parse("5564B5F0-0292-E711-8122-E3FE48DB937B"));
trial.new_Notes = "this is test plugin using c#";
xrm.AddObject(trial);
xrm.SaveChanges();
}
trial.Attributes["new_LookupTransactionHeader"] = new EntityReference("new_transactionheader", new_transactionheaderId-GUID);
You have to use EntityReference like above to setup lookup attribute.

Product_Order verifyOrder API fails when adding guest_disks

I have a C# application in which I imported API methods using wsdl, as described in the Softlayer guidelines.
I'm editing virtual guests by passing a Container_Product_Order_Virtual_Guest_Upgrade structure to the Product_Order service.
Everything works great except for when adding item price IDs for guest_disks, scenario in which after about 6-7 seconds the following exception is thrown:
"The request was aborted: The connection was closed unexpectedly."
This happens with both verifyOrder and placeOrder methods.
I checked Virtual_Guest::getUpgradeItemPrices in order to make sure that the guest disk values are valid(even though passing invalid itempriceIds for the VM results in an specific error response, not in a generic exception such as the one described above).
I can't find any details in the documentation that could give me hints as why I can upgrade anything except guest_disks.
EDIT:
Stripped code as requested:
SoftLayer_Virtual_Guest[] _VMtoEditList = new SoftLayer_Virtual_Guest[1] { -- Vm instance details are retrieved from SL according to the passed VM ID; };
List<SoftLayer_Product_Item_Price> _itemPriceList = new List<SoftLayer_Product_Item_Price>();
foreach (-- collection of properties to be upgraded )
{
SoftLayer_Product_Item_Category _category = new SoftLayer_Product_Item_Category();
_category.categoryCode = -- retrieved from the collection on which I iterate (eg "guest_disk0", "ram", etc.);
SoftLayer_Product_Item_Price _itemPrice = new SoftLayer_Product_Item_Price();
_itemPrice.id = -- the item priceID for the current item;
_itemPrice.idSpecified = true;
_itemPrice.categories = new SoftLayer_Product_Item_Category[1] { _category };
_itemPriceList.Add(_itemPrice);
}
SoftLayer_Product_Item_Price[] _itemPricesArray = _itemPriceList.ToArray();
SoftLayer_Container_Product_Order_Property _property1 = new SoftLayer_Container_Product_Order_Property();
_property1.name = "NOTE_GENERAL";
_property1.value = -- order's description;
SoftLayer_Container_Product_Order_Property _property2 = new SoftLayer_Container_Product_Order_Property();
_property2.name = "MAINTENANCE_WINDOW";
_property2.value = "now";
// Build SoftLayer_Container_Product_Order_Property
SoftLayer_Container_Product_Order_Property[] properties = new SoftLayer_Container_Product_Order_Property[2] { _property1, _property2 };
-- create container
SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade _upgradeContainer = new SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade();
_upgradeContainer.virtualGuests = _VMtoEditList;
_upgradeContainer.prices = _itemPricesArray;
_upgradeContainer.properties = properties;
_upgradeContainer.packageId = 46;
_upgradeContainer.packageIdSpecified = true;
SoftLayer_Product_OrderService service = new SoftLayer_Product_OrderService();
-- authentication structure is created here
SoftLayer_Container_Product_Order _verifiedOrder = service.verifyOrder(_upgradeContainer);
service.placeOrder(_verifiedOrder, false);
Here a have an example to upgrade which works see below. I see that in your code you are adding the packageId which is not required, removed and try again.
Also when you are creating the web references try using the last version of the api in the WSDL url (v3.1)
e.g. https://api.softlayer.com/soap/v3.1/SoftLayer_Hardware_Server?wsdl
//-----------------------------------------------------------------------
// <copyright file="PlaceOrderUpgrade.cs" company="Softlayer">
// SoftLayer Technologies, Inc.
// </copyright>
// <license>
// http://sldn.softlayer.com/article/License
// </license>
//-----------------------------------------------------------------------
namespace VirtualGuests
{
using System;
using System.Collections.Generic;
class PlaceOrderUpgrade
{
/// <summary>
/// Order an upgrade for Virtual Guest
/// This script orders an upgrade for Virtual Guest, in this case we will upgrade the ram for a Virtual Guest,
/// It uses SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade container and SoftLayer_Product_Order::placeOrder
/// method for it.
/// For more information, review the following links:
/// </summary>
/// <manualPages>
/// http://sldn.softlayer.com/reference/services/SoftLayer_Product_Order/placeOrder
/// http://sldn.softlayer.com/reference/datatypes/SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade/
/// http://sldn.softlayer.com/reference/services/SoftLayer_Product_Item_Price/
/// </manualPages>
static void Main(String [] args)
{
// You SoftLayer username
string username = "set me";
// Your SoftLayer API key.
string apiKey = "set me";
// Define the virtual guest id to place an upgrade
int virtualId = 13115425;
// Creating a connection to the SoftLayer_Product_Order API service and
// bind our API username and key to it.
authenticate authenticate = new authenticate();
authenticate.username = username;
authenticate.apiKey = apiKey;
SoftLayer_Product_OrderService orderService = new SoftLayer_Product_OrderService();
orderService.authenticateValue = authenticate;
// Build a SoftLayer_Product_Item_Price objects with the ids from prices that you want to order.
// You can retrieve them with SoftLayer_Product_Package::getItemPrices method
int[] prices = {
1645
};
List<SoftLayer_Product_Item_Price> pricesList = new List<SoftLayer_Product_Item_Price>();
foreach (var price in prices)
{
SoftLayer_Product_Item_Price newPrice = new SoftLayer_Product_Item_Price();
newPrice.id = price;
newPrice.idSpecified = true;
pricesList.Add(newPrice);
}
// Build SoftLayer_Container_Product_Order_Property object for the upgrade
SoftLayer_Container_Product_Order_Property property = new SoftLayer_Container_Product_Order_Property();
property.name = "MAINTENANCE_WINDOW";
property.value = "NOW";
List<SoftLayer_Container_Product_Order_Property> propertyList = new List<SoftLayer_Container_Product_Order_Property>();
propertyList.Add(property);
// Build SoftLayer_Virtual_Guest object with the id from vsi that you wish to place an upgrade
SoftLayer_Virtual_Guest virtualGuest = new SoftLayer_Virtual_Guest();
virtualGuest.id = virtualId;
virtualGuest.idSpecified = true;
List<SoftLayer_Virtual_Guest> virtualGuests = new List<SoftLayer_Virtual_Guest>();
virtualGuests.Add(virtualGuest);
// Build SoftLayer_Container_Product_Order object containing the information for the upgrade
//SoftLayer_Container_Product_Order orderTemplate = new SoftLayer_Container_Product_Order();
SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade orderTemplate = new SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade();
orderTemplate.containerIdentifier = "SoftLayer_Container_Product_Order_Virtual_Guest_Upgrade";
orderTemplate.prices = pricesList.ToArray();
orderTemplate.properties = propertyList.ToArray();
orderTemplate.virtualGuests = virtualGuests.ToArray();
try
{
// We will check the template for errors, we will use the verifyOrder() method for this.
// Replace it with placeOrder() method when you are ready to order.
SoftLayer_Container_Product_Order verifiedOrder = orderService.verifyOrder(orderTemplate);
Console.WriteLine("Order Verified!");
}
catch (Exception e)
{
Console.WriteLine("Unable to place an upgrade for Virtual Guest: " + e.Message);
}
}
}
}
Let me know if this helps
Regards

Get data from to field in new activity in CRM 2011

I create a new plugin for dynamic CRM 2011 for a costume Activity Entity.
this new activity have "to" field like Email and some other activities.
plugin are working on Create and Update steps for activity.
my problem is when i want to get "to" field value the below line of code return false value and i don't know what i have done. in fact i can fetch other custom field and just the "to" field does not work.
if (entity3.Attributes.Contains("to"))
and this is whole code:
public void Execute(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
{
throw new ArgumentNullException("serviceProvider");
}
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") && (context.InputParameters["Target"] is Entity))
{
Entity entity2 = (Entity)context.InputParameters["Target"];
if (entity2.LogicalName == "EntityAtivity")
{
QueryExpression expression3 = new QueryExpression("EntityAtivity");
ColumnSet set2 = new ColumnSet();
set2.AllColumns = true;
expression3.ColumnSet = set2;
ConditionExpression item = new ConditionExpression();
item.AttributeName = "activityid";
CurrentGuid = (Guid)entity2.Attributes["activityid"];
item.Values.Add(this.CurrentGuid);
FilterExpression expression5 = new FilterExpression();
expression5.Conditions.Add(item);
expression3.Criteria = expression5;
EntityCollection entitys2 = service.RetrieveMultiple(expression3);
foreach (Entity entity3 in entitys2.Entities)
{
this.dbGuid = (Guid)entity3.Attributes["activityid"];
if (entity3.Attributes.Contains("to"))
{
try
{
foreach (Entity entity10 in ((EntityCollection)entity3.Attributes["to"]).Entities)
{
this.dbTo.Add(((EntityReference)entity10.Attributes["partyid"]).LogicalName);
this.dbToId.Add(((EntityReference)entity10.Attributes["partyid"]).Id);
}
}
catch (Exception)
{
this.dbTo.Clear();
}
}
} // foreach
}//if (entity2.LogicalName == "EntityAtivity")
}//if (context.InputParameters.Contains("Target") && (context.InputParameters["Target"] is Entity))
}
any know what i should done to correct plugin?
Your question and answer is hard to understand because your English could use some work, but I believe your issue is that you're looking for an attribute in the target of a value that hasn't been set. If an attribute hasn't been set or updated, it will not show up in the target of the the plugin. As #AndyMeyers says, you should use the PreImage and PostImage images to define what attributes you always want to be included in the processing of your plugin.
So i solve my problem.
i create 2 steps, for Create and Update.
when i disable the Create Step and create pre image for update step, plug in fetch to field and show the values.

Categories

Resources