In CRM 2013, when a Lead is set as Qualified by the user, the lead is converted into a Opportunity. When this happens a record is also created in the entity Contact and Account. When a plugin is involved in the process it is necessary in the plugin to use the following code
if (context.MessageName.ToLower() == "create" && entity.Attributes.Contains("originatingleadid") && entity["originatingleadid"] != null)
{
return;
}
else
{
//plugin code
}
So that the plugin only executes when a contact / account is created and not when a lead is being converted to a opportunity
My question is how is this achievable when a Quote is being converted to a Order as when I am doing this process my plugin for Order is being activated and is throwing a business process error as 'the given key is not present in the dictionary'
You should create a plugin which is registered to Pre/Post Operation of Order creation. Then, in your plugin in you should check for quoteid:
if (entity.Attributes.Contains("quoteid") &&
entity["quoteid"] != null)
{
return;
}
else
{
//plugin code
}
Hope it helps!
Related
I am working on a Custom Workflow within CRM 2011. I have created the workflow to create a couple of records (invoice and invoice product) once I get a particular type of Activity (a custom activity). During the testing I passed the particular GUID of the entity I would be working with (the creation of said entity would be the trigger for the workflow). The workflow works fine when I pass in a GUID for the record I want to work with. However, once I load the dll File inside CRM and attempt to trigger the workflow it goes into a waiting status and stays there. I have try catch blocks on all of my functions with a throw new InvalidPluginExecutionException("Error occurred in MethodName:" + ex.Message);. It does not fail or stop but just continues in a waiting status.
I have tried to Reset :
IIS
async service
Sync Services
(Have Tried Edit:
Adding Version Control
Uninstall / Reinstall assembly)
Currently I am attempting to pull the activity id of the PrimaryEntityId as my primary entity is the record I need to use for the workflow. The only thing that I need from that record is the ID.
public String GetFeeId(WorkFlowHelper workFlowHelper, CodeActivityContext executionContext)
{
String feeRecordId = string.Empty;
try
{
var primaryEntity = workFlowHelper.workFlowContext.PrimaryEntityId;
if (primaryEntity != null)
{
feeRecordId = workFlowHelper.workFlowContext.PrimaryEntityId.ToString();
}
if (primaryEntity == null)
{
workFlowHelper.WorkFlowError("Primary Entity is null");
}
}
catch (Exception ex)
{
if (workFlowHelper.debugMessagesOn == true)
{
Console.WriteLine("Id is blank!");
}
workFlowHelper.WorkFlowError(ex.ToString());
throw new InvalidPluginExecutionException("Error occured in ConnectionInfo Method:" + ex.Message);
}
return feeRecordId;
Any ideas on what could be causing this?
Thanks,
It sounds like CRM may be having a problem loading your assembly, or confusing it for an older version of the same assembly.
Are you versioning your workflow assembly while you develop and deploy it, and is the assembly signed with a strong-name key?
In Visual Studio on the Project tab, make sure you increment the Build/Revision number. See this article: http://gonzaloruizcrm.blogspot.com/2011/08/assembly-versioning-in-crm-2011.html
If you don't increment the Build/Revision, CRM may not see your updated assembly as an "update" and may be trying to use an older, cached version, which can cause all kinds of problems.
You may also try unregistering the assembly completely and then registering your latest version. You might need to update your workflows as well.
Here's the most simplest way (taken out your WorkFlowHelper)..
public String GetFeeId(CodeActivityContext executionContext)
{
// Create the context
var context = executionContext.GetExtension<IWorkflowContext>();
var feeRecordId = context.PrimaryEntityId
}
I am currently using InvalidPluginExecutionException to send the message to the user, but it turns out that the message is in English "Business Process Error" beyond which the error box appears the button "download log file". This is not an error because the user is trying to duplicate a record, as can be seen in the code. Is there other way without having to use InvalidPluginExecutionException to show an alert?
QueryExpression query1 = new QueryExpression();
query1.ColumnSet = new ColumnSet(true);
query1.EntityName = "new_appraisers";
EntityCollection ec = service.RetrieveMultiple(query1);
if (ec.Entities.Count <= 0)
{
log.Tb_Log_Create("Appraiser created");
}
else
{
foreach (Entity app in ec.Entities)
{
if (app["fcg_appraiser"].ToString() == name)
{
log.Tb_Log_Create("appraiser allready exist");
throw new InvalidPluginExecutionException("The name allready exists");
}
if (app["new_login"].ToString() == login)
{
log.Tb_Log_Create("appraiser allready exist");
throw new InvalidPluginExecutionException("The login allready exists.");
}
}
}
The only method to display a message box to the user from a plugin is using an exception from the validation stage. You could use javascript however, perform a simple OData query on the On_Save event of the form, and display an alert box with whatever information you'd like, and cancel the saving of the form.
This would allow you to display whatever custom message you'd like, and keep the plugin from firing and displaying the download file dialog.
I may be little late, however, in more recent versions of CRM there are several possibilites to achieve what you want. The better ones beeing:
Business Rules
Validation using JS and notifying the user using
Form Notifications or
Control Notifications
I hope Microsoft doesn't read this but...
You can also use a synchronous Plugin and be happy with the Business Process Error Dialog popping off. I just found out that this Dialog is hackable to some degree. Just return HTML in the Exeptions Message like so:
throw new InvalidPluginExecutionException(
#"<img height='16px' src='http://emojione.com/wp-content/uploads/assets/emojis/1f644.svg'> <strong>Oh snap!</strong>
It seems the record can not be saved in its current state.
");
Which results in sth. like this:
I thought this would be a lot easier, however I'm unable to find a way to determine in my event handler if it is the FIRST check-in of the file..
You see, I'm breaking role inheritance, and selectively inheriting permissions for files in doc libs, yet I wish to do it only once, during the first check-in of the file.
I've tried adding an entry to 'SPListItem.Properties' in the ItemAdded event in order to indicate if the file is new, however the moment I do 'SPListItem.Update()' it vanishes..
I've played with the ItemCheckingIn and ItemCheckedIn events with no success...
My only hope at the moment is adding a SPField to the ContentType to indicate if new file or not, but I really wish to avoid it..
ANY IDEAS????
PLEASE HELP ME!
I would recommend considering not only whether the system account has access, but also if the checked out date of the file is identical to the file's creation date.
public bool IsFirstCheckIn(SPListItem item)
{
// Item not null!
if (item != null)
{
SPSecurity.RunWithElevatedPrivileges(delegate
{
// Open privileged Site
using (SPSite pSite = new SPSite(site.ID))
{
// Open privileged Web
using (SPWeb pWeb = pSite.OpenWeb(web.ID))
{
// Create privileged SharePoint-Objects
SPList pList = GetList(pWeb, list.ID);
SPListItem pItem = GetListItem(pList, item.UniqueId);
// Check the Item
if (pItem == null)
{
// Can't access
return true;
}
else if (pItem.File != null && pItem.File.CheckedOutByUser != null)
{
// If the Item's File and checked out User is set, check if checked out date is equal creation date
return (pItem.File.CheckedOutDate.ToLocalTime() == pItem.File.TimeCreated.ToLocalTime());
}
}
}
});
}
return false;
}
To use the system account, is definitely a good idea, otherwise authorization settings would cause problems. Use the "local time" instead of the "UTC-Time", SharePoint handled the Time Zone while storing!
Seems like, SharePoint used the UTF-FileTime to store the file's creation time but used the Time Zone defined for the SPWeb or for the SPUser to store the file checked out date based on the "local time".
Fortunately the DateTime value does know what it is and can convert it to the same "local time" while calling ToLocalTime(). Strangely it will be still a File-Time while calling ToUniversalTime();
So I got a solution for this.
I'm sorry I can't post code here, I do not have access to internet on my dev machine.
It should be good enough for everyone.
Solution:
During the CheckingIn event I try to access the file using the SHAREPOINT\system("SPSecurity.RunWithElevatedPrivileges()"). During the first check-in the file is new and not accessible to other users besides the uploader.
So if I fail getting the file with SHAREPOINT\system it means its new, and I save its Guid in a dictionary in my EventHandlers class.
Then in the CheckedIn event I simply check if the dictionary contains the Guid of the current item, if it does - FIRST CHECK-IN, if it does not - NOT FIRST CHECK-IN.
Of course after I'm finished with the file I remove the entry from the dictionary.
Hope it helps, if you got any questions you are welcome to ask :)
I'm try to use Vista TaskDialog Wrapper and Emulator and I'm getting the following exception:
"Unable to find an entry point named 'TaskDialogIndirect' in DLL 'ComCtl32'."
...in a simple Console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
System.Threading.Thread.CurrentThread.CurrentUICulture = System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
PSTaskDialog.cTaskDialog.MessageBox(
"MessageBox Title",
"The main instruction text for the message box is shown here.",
"The content text for the message box is shown here and the text willautomatically wrap as needed.",
PSTaskDialog.eTaskDialogButtons.YesNo,
PSTaskDialog.eSysIcons.Information
);
}
}
What am I doing wrong?
UPDATE:
Actually, I'm working on an Excel plugin using excel-dna. How can I control what dll Excel loads?
http://exceldna.codeplex.com/discussions/286990#post728888
I haven't been at Office programming in a while, but my guess is that Excel loads both versions of comctl32, so you may need to use the Activation Context API to direct your code to the version that includes TaskDialog. Some ideas for fixing the problem (not solutions as such):
For test purposes, make a temporary enumeration of all modules in the active process - just to check if 6.10 is actually loaded (see below for a simple example of such an enumeration, albeit with a different intent).
Use the Activation Context API to get to the right version. Example of use from C# (for enabling themes by way of comctl32 6.0) here.
Alternatively (I never actually got this to work reliably in a WPF application I worked on), make a dialog abstraction class, which falls back to MessageDlg depending on the version available to you. There may be better ways of doing the check, but...:
FileVersionInfo version = ProcessUtils.GetLoadedModuleVersion("comctl32.dll");
if (version != null && version.FileMajorPart >= 6 && version.FileMinorPart >= 1)
{
// We can use TaskDialog...
}
else
{
// Use old style MessageBox
}
The enumeration of modules:
internal static FileVersionInfo GetLoadedModuleVersion(string name)
{
Process process = Process.GetCurrentProcess();
foreach (ProcessModule module in process.Modules)
{
if (module.ModuleName.ToLower() == name)
{
return module.FileVersionInfo;
}
return null;
}
}
In addition to what all the others are saying: This error will disappear if you set the ForceEmulationMode on PSTaskDialog to true.
I need to play PowerPoint slides but first I want to check whether PowerPoint or viewer is installed on the machine or not. How can I do that using .NET?
It depends on whether you are trying to tell whether you can view a presentation (*.ppt, *.pptx, etc) or whether you can access the PowerPoint object model.
To check whether there is an associated handler for ppt files, you can do the following:
// using Microsoft.Win32;
private bool CheckPowerPointAssociation() {
var key = Registry.ClassesRoot.OpenSubKey(".ppt", false);
if (key != null) {
key.Close();
return true;
}
else {
return false;
}
}
if (CheckPowerPointAssociation()) {
Process.Start(pathToPPT);
}
To check whether the PowerPoint COM object model is available, you can check the following registry key.
// using Microsoft.Win32;
private bool CheckPowerPointAutomation() {
var key = Registry.ClassesRoot.OpenSubKey("PowerPoint.Application", false);
if (key != null) {
key.Close();
return true;
}
else {
return false;
}
}
if (CheckPowerPointAutomation()) {
var powerPointApp = new Microsoft.Office.Interop.PowerPoint.Application();
....
}
Note, however, that in both cases it will only give you a pretty good indication of the availability of PowerPoint. For example, an uninstallation may not have fully removed all traces. Also in my experience selling an Outlook addin for years I've seen certain antivirus programs that interfere with the COM object model in a screwup effort to protect against malicious scripts. So in any case, have robust error handling as well.
Hope this helps!
HKEY_CLASSES_ROOT\MSPowerPoint\protocol\StdFileEditing\server
This key is the same for all installs of PowerPoint and points to the install dir for the executable to run PowerPoint. Great to use when detecting if this product is installed and good for figuring out which folder Office products are installed in, when the install is not using the defaults.
I am not sure this is the right way to do this. But you can use this
try
{
//It will throw a WIN32 Exception if there is no associated
//application available to open the file.
Process p = Process.Start("C:\\Sample.pptx");
}
catch (Win32Exception ex)
{
MessageBox.Show("Powerpoint or Powerpoint viewer not installed\n");
}
What about checking if the EXE file for PowerPoint or PowerPoint viewer exists or not by using "Exists Method" from system.io namespace?
Check this.