Last active
May 14, 2018 15:00
-
-
Save carfup/5f46f6d9264282433405d52c1ca44f67 to your computer and use it in GitHub Desktop.
PluginClass which allows to send Exception details to a WebHook
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// <copyright file="Plugin.cs" company=""> | |
// Copyright (c) 2014 All Rights Reserved | |
// </copyright> | |
// <author></author> | |
// <date>18/11/2014 17:48:14</date> | |
// <summary>Implements the Plugin Workflow Activity.</summary> | |
// <auto-generated> | |
// This code was generated by a tool. | |
// Runtime Version:4.0.30319.1 | |
// </auto-generated> | |
namespace Plugins | |
{ | |
using System; | |
using System.Collections.ObjectModel; | |
using System.Globalization; | |
using System.Linq; | |
using System.Net.Http; | |
using System.ServiceModel; | |
using System.Text; | |
using Microsoft.Xrm.Sdk; | |
/// <summary> | |
/// Base class for all Plugins. | |
/// </summary> | |
public class Plugin : IPlugin | |
{ | |
protected class LocalPluginContext | |
{ | |
internal IServiceProvider ServiceProvider | |
{ | |
get; | |
private set; | |
} | |
internal IOrganizationService OrganizationService | |
{ | |
get; | |
private set; | |
} | |
internal IPluginExecutionContext PluginExecutionContext | |
{ | |
get; | |
private set; | |
} | |
internal ITracingService TracingService | |
{ | |
get; | |
private set; | |
} | |
private LocalPluginContext() | |
{ | |
} | |
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)); | |
// Use the factory to generate the Organization Service. | |
this.OrganizationService = factory.CreateOrganizationService(this.PluginExecutionContext.UserId); | |
} | |
internal void Trace(string message) | |
{ | |
if (string.IsNullOrWhiteSpace(message) || this.TracingService == null) | |
{ | |
return; | |
} | |
if (this.PluginExecutionContext == null) | |
{ | |
this.TracingService.Trace(message); | |
} | |
else | |
{ | |
this.TracingService.Trace( | |
"{0}, Correlation Id: {1}, Initiating User: {2}", | |
message, | |
this.PluginExecutionContext.CorrelationId, | |
this.PluginExecutionContext.InitiatingUserId); | |
} | |
} | |
} | |
private Collection<Tuple<int, string, string, Action<LocalPluginContext>>> registeredEvents; | |
/// <summary> | |
/// Gets the List of events that the plug-in should fire for. Each List | |
/// Item is a <see cref="System.Tuple"/> containing the Pipeline Stage, Message and (optionally) the Primary Entity. | |
/// In addition, the fourth parameter provide the delegate to invoke on a matching registration. | |
/// </summary> | |
protected Collection<Tuple<int, string, string, Action<LocalPluginContext>>> RegisteredEvents | |
{ | |
get | |
{ | |
if (this.registeredEvents == null) | |
{ | |
this.registeredEvents = new Collection<Tuple<int, string, string, Action<LocalPluginContext>>>(); | |
} | |
return this.registeredEvents; | |
} | |
} | |
/// <summary> | |
/// Gets or sets the name of the child class. | |
/// </summary> | |
/// <value>The name of the child class.</value> | |
protected string ChildClassName | |
{ | |
get; | |
private set; | |
} | |
/// <summary> | |
/// Initializes a new instance of the <see cref="Plugin"/> class. | |
/// </summary> | |
/// <param name="childClassName">The <see cref=" cred="Type"/> of the derived class.</param> | |
internal Plugin(Type childClassName) | |
{ | |
this.ChildClassName = childClassName.ToString(); | |
} | |
/// <summary> | |
/// Executes the plug-in. | |
/// </summary> | |
/// <param name="serviceProvider">The service provider.</param> | |
/// <remarks> | |
/// For improved performance, Microsoft Dynamics CRM caches plug-in instances. | |
/// The plug-in's Execute method should be written to be stateless as the constructor | |
/// is not called for every invocation of the plug-in. Also, multiple system threads | |
/// could execute the plug-in at the same time. All per invocation state information | |
/// is stored in the context. This means that you should not use global variables in plug-ins. | |
/// </remarks> | |
public void Execute(IServiceProvider serviceProvider) | |
{ | |
if (serviceProvider == null) | |
{ | |
throw new ArgumentNullException("serviceProvider"); | |
} | |
// Construct the Local plug-in context. | |
LocalPluginContext localcontext = new LocalPluginContext(serviceProvider); | |
localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Entered {0}.Execute()", this.ChildClassName)); | |
try | |
{ | |
// Iterate over all of the expected registered events to ensure that the plugin | |
// has been invoked by an expected event | |
// For any given plug-in event at an instance in time, we would expect at most 1 result to match. | |
Action<LocalPluginContext> entityAction = | |
(from a in this.RegisteredEvents | |
where ( | |
a.Item1 == localcontext.PluginExecutionContext.Stage && | |
a.Item2 == localcontext.PluginExecutionContext.MessageName && | |
(string.IsNullOrWhiteSpace(a.Item3) ? true : a.Item3 == localcontext.PluginExecutionContext.PrimaryEntityName) | |
) | |
select a.Item4).FirstOrDefault(); | |
if (entityAction != null) | |
{ | |
localcontext.Trace(string.Format( | |
CultureInfo.InvariantCulture, | |
"{0} is firing for Entity: {1}, Message: {2}, Guid : {3}", | |
this.ChildClassName, | |
localcontext.PluginExecutionContext.PrimaryEntityName, | |
localcontext.PluginExecutionContext.MessageName, | |
localcontext.PluginExecutionContext.PrimaryEntityId)); | |
entityAction.Invoke(localcontext); | |
// now exit - if the derived plug-in has incorrectly registered overlapping event registrations, | |
// guard against multiple executions. | |
return; | |
} | |
} | |
// Starting the custom code to handle the webhook and exception | |
catch (InvalidPluginExecutionException ex) | |
{ | |
try | |
{ | |
IServiceEndpointNotificationService cloudService = (IServiceEndpointNotificationService)serviceProvider.GetService(typeof(IServiceEndpointNotificationService)); | |
if (cloudService == null) | |
throw new InvalidPluginExecutionException("Failed to retrieve the service bus service."); | |
localcontext.PluginExecutionContext.SharedVariables.Add("EntityName", localcontext.PluginExecutionContext.PrimaryEntityName); | |
localcontext.PluginExecutionContext.SharedVariables.Add("PluginAction", localcontext.PluginExecutionContext.MessageName); | |
localcontext.PluginExecutionContext.SharedVariables.Add("ExceptionMessage", ex.Message); | |
localcontext.PluginExecutionContext.SharedVariables.Add("ExceptionStackTrace", ex.StackTrace); | |
string response = cloudService.Execute(new EntityReference("serviceendpoint", new Guid("ServiceEndPointGuid")), localcontext.PluginExecutionContext); | |
} | |
catch {} | |
throw; | |
} | |
// End of the custom code to handle the webhook and exception | |
catch (FaultException<OrganizationServiceFault> e) | |
{ | |
localcontext.Trace(string.Format("{0}.Execute() Exception: {1} : {2}", | |
this.ChildClassName, | |
e.ToString(), e.StackTrace)); | |
// Handle the exception. | |
throw; | |
} | |
finally | |
{ | |
localcontext.Trace(string.Format(CultureInfo.InvariantCulture, "Exiting {0}.Execute()", this.ChildClassName)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment