MSMQ binding mismatch - c#

We have a setup that used to work and has stopped sometime over the past few months. We use a custom dead-letter queue that is specified in config but basically gets set like this::
MsmqIntegrationBinding msmq = new MsmqIntegrationBinding(
// Defaults to WindowsDomain. We want all messages to be authenticated.
MsmqIntegrationSecurityMode.Transport);
msmq.DeadLetterQueue = DeadLetterQueue.Custom;
msmq.CustomDeadLetterQueue = new Uri("net.msmq://localhost/private/BulkUpdatesDeadLetter");
We've started getting this error, which seems to be pretty clear:
System.InvalidOperationException: A mismatch occurred between the binding and the MSMQ configuration. Messages cannot be sent. The custom dead letter queue specified in the binding must be a transactional queue. Ensure that the custom dead letter queue address is correct and the queue is a transactional queue.
We've verified both that we are pointing to the correct queue in the config and that the queue is transactional. Are there any other issues that might cause this exception to be thrown, or are we just missing something in the obvious?
Update: Had our web ops team delete and recreate the queues and still receiving the error.

The following code is provided by Microsoft corporation in the article BindingsSection.cs source code in C# .NET
namespace System.ServiceModel.Configuration
{
using System.Configuration;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Xml;
using System.Security;
public sealed partial class BindingsSection : ConfigurationSection, IConfigurationContextProviderInternal
{
static Configuration configuration = null;
ConfigurationPropertyCollection properties;
public BindingsSection() { }
Dictionary<string, bindingcollectionelement=""> BindingCollectionElements
{
get
{
Dictionary<string, bindingcollectionelement=""> bindingCollectionElements = new Dictionary<string, bindingcollectionelement="">();
foreach (ConfigurationProperty property in this.Properties)
{
bindingCollectionElements.Add(property.Name, this[property.Name]);
}
return bindingCollectionElements;
}
}
new public BindingCollectionElement this[string binding]
{
get
{
return (BindingCollectionElement)base[binding];
}
}
protected override ConfigurationPropertyCollection Properties
{
get
{
if (this.properties == null)
{
this.properties = new ConfigurationPropertyCollection();
}
this.UpdateBindingSections();
return this.properties;
}
}
[ConfigurationProperty(ConfigurationStrings.BasicHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public BasicHttpBindingCollectionElement BasicHttpBinding
{
get { return (BasicHttpBindingCollectionElement)base[ConfigurationStrings.BasicHttpBindingCollectionElementName]; }
}
// This property should only be called/set from BindingsSectionGroup TryAdd
static Configuration Configuration
{
get { return BindingsSection.configuration; }
set { BindingsSection.configuration = value; }
}
[ConfigurationProperty(ConfigurationStrings.CustomBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public CustomBindingCollectionElement CustomBinding
{
get { return (CustomBindingCollectionElement)base[ConfigurationStrings.CustomBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.MsmqIntegrationBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public MsmqIntegrationBindingCollectionElement MsmqIntegrationBinding
{
get { return (MsmqIntegrationBindingCollectionElement)base[ConfigurationStrings.MsmqIntegrationBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetPeerTcpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetPeerTcpBindingCollectionElement NetPeerTcpBinding
{
get { return (NetPeerTcpBindingCollectionElement)base[ConfigurationStrings.NetPeerTcpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetMsmqBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetMsmqBindingCollectionElement NetMsmqBinding
{
get { return (NetMsmqBindingCollectionElement)base[ConfigurationStrings.NetMsmqBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetNamedPipeBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetNamedPipeBindingCollectionElement NetNamedPipeBinding
{
get { return (NetNamedPipeBindingCollectionElement)base[ConfigurationStrings.NetNamedPipeBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.NetTcpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public NetTcpBindingCollectionElement NetTcpBinding
{
get { return (NetTcpBindingCollectionElement)base[ConfigurationStrings.NetTcpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WSFederationHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WSFederationHttpBindingCollectionElement WSFederationHttpBinding
{
get { return (WSFederationHttpBindingCollectionElement)base[ConfigurationStrings.WSFederationHttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WS2007FederationHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WS2007FederationHttpBindingCollectionElement WS2007FederationHttpBinding
{
get { return (WS2007FederationHttpBindingCollectionElement)base[ConfigurationStrings.WS2007FederationHttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WSHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WSHttpBindingCollectionElement WSHttpBinding
{
get { return (WSHttpBindingCollectionElement)base[ConfigurationStrings.WSHttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WS2007HttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WS2007HttpBindingCollectionElement WS2007HttpBinding
{
get { return (WS2007HttpBindingCollectionElement)base[ConfigurationStrings.WS2007HttpBindingCollectionElementName]; }
}
[ConfigurationProperty(ConfigurationStrings.WSDualHttpBindingCollectionElementName, Options = ConfigurationPropertyOptions.None)]
public WSDualHttpBindingCollectionElement WSDualHttpBinding
{
get { return (WSDualHttpBindingCollectionElement)base[ConfigurationStrings.WSDualHttpBindingCollectionElementName]; }
}
public static BindingsSection GetSection(Configuration config)
{
if (config == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("config");
}
return (BindingsSection)config.GetSection(ConfigurationStrings.BindingsSectionGroupPath);
}
public List<bindingcollectionelement> BindingCollections
{
get
{
List<bindingcollectionelement> bindingCollections = new List<bindingcollectionelement>();
foreach (ConfigurationProperty property in this.Properties)
{
bindingCollections.Add(this[property.Name]);
}
return bindingCollections;
}
}
internal static bool TryAdd(string name, Binding binding, Configuration config, out string bindingSectionName)
{
bool retval = false;
BindingsSection.Configuration = config;
try
{
retval = BindingsSection.TryAdd(name, binding, out bindingSectionName);
}
finally
{
BindingsSection.Configuration = null;
}
return retval;
}
internal static bool TryAdd(string name, Binding binding, out string bindingSectionName)
{
// TryAdd built on assumption that BindingsSectionGroup.Configuration is valid.
// This should be protected at the callers site. If assumption is invalid, then
// configuration system is in an indeterminate state. Need to stop in a manner that
// user code can not capture.
if (null == BindingsSection.Configuration)
{
DiagnosticUtility.DebugAssert("The TryAdd(string name, Binding binding, Configuration config, out string binding) variant of this function should always be called first. The Configuration object is not set.");
DiagnosticUtility.FailFast("The TryAdd(string name, Binding binding, Configuration config, out string binding) variant of this function should always be called first. The Configuration object is not set.");
}
bool retval = false;
string outBindingSectionName = null;
BindingsSection sectionGroup = BindingsSection.GetSection(BindingsSection.Configuration);
sectionGroup.UpdateBindingSections();
foreach (string sectionName in sectionGroup.BindingCollectionElements.Keys)
{
BindingCollectionElement bindingCollectionElement = sectionGroup.BindingCollectionElements[sectionName];
// Save the custom bindings as the last choice
if (!(bindingCollectionElement is CustomBindingCollectionElement))
{
MethodInfo tryAddMethod = bindingCollectionElement.GetType().GetMethod("TryAdd", BindingFlags.Instance | BindingFlags.NonPublic);
if (tryAddMethod != null)
{
retval = (bool)tryAddMethod.Invoke(bindingCollectionElement, new object[] { name, binding, BindingsSection.Configuration });
if (retval)
{
outBindingSectionName = sectionName;
break;
}
}
}
}
if (!retval)
{
// Much of the time, the custombinding should come out ok.
CustomBindingCollectionElement customBindingSection = CustomBindingCollectionElement.GetBindingCollectionElement();
retval = customBindingSection.TryAdd(name, binding, BindingsSection.Configuration);
if (retval)
{
outBindingSectionName = ConfigurationStrings.CustomBindingCollectionElementName;
}
}
// This little oddity exists to make sure that the out param is assigned to before the method
// exits.
bindingSectionName = outBindingSectionName;
return retval;
}
/// <securitynote>
/// Critical - uses SecurityCritical method UnsafeLookupCollection which elevates
/// Safe - does not leak config objects
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe]
void UpdateBindingSections()
{
ExtensionElementCollection bindingExtensions = ExtensionsSection.UnsafeLookupCollection(ConfigurationStrings.BindingExtensions, ConfigurationHelpers.GetEvaluationContext(this));
// Extension collections are additive only (BasicMap) and do not allow for <clear>
// or <remove> tags, nor do they allow for overriding an entry. This allows us
// to optimize this to only walk the binding extension collection if the counts
// mismatch.
if (bindingExtensions.Count != this.properties.Count)
{
foreach (ExtensionElement bindingExtension in bindingExtensions)
{
if (null != bindingExtension)
{
if (!this.properties.Contains(bindingExtension.Name))
{
ConfigurationProperty property = new ConfigurationProperty(bindingExtension.Name,
Type.GetType(bindingExtension.Type, true),
null,
ConfigurationPropertyOptions.None);
this.properties.Add(property);
}
}
}
}
}
/// <securitynote>
/// Critical - uses SecurityCritical method UnsafeGetAssociatedBindingCollectionElement which elevates
/// Safe - does not leak config objects
/// </securitynote>
[SecurityCritical, SecurityTreatAsSafe]
internal static void ValidateBindingReference(string binding, string bindingConfiguration, ContextInformation evaluationContext, ConfigurationElement configurationElement)
{
// ValidateBindingReference built on assumption that evaluationContext is valid.
// This should be protected at the callers site. If assumption is invalid, then
// configuration system is in an indeterminate state. Need to stop in a manner that
// user code can not capture.
if (null == evaluationContext)
{
DiagnosticUtility.DebugAssert("ValidateBindingReference() should only called with valid ContextInformation");
DiagnosticUtility.FailFast("ValidateBindingReference() should only called with valid ContextInformation");
}
if (!String.IsNullOrEmpty(binding))
{
BindingCollectionElement bindingCollectionElement = null;
if (null != evaluationContext)
{
bindingCollectionElement = ConfigurationHelpers.UnsafeGetAssociatedBindingCollectionElement(evaluationContext, binding);
}
else
{
bindingCollectionElement = ConfigurationHelpers.UnsafeGetBindingCollectionElement(binding);
}
if (bindingCollectionElement == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigInvalidSection,
ConfigurationHelpers.GetBindingsSectionPath(binding)),
configurationElement.ElementInformation.Source,
configurationElement.ElementInformation.LineNumber));
}
if (!String.IsNullOrEmpty(bindingConfiguration))
{
if (!bindingCollectionElement.ContainsKey(bindingConfiguration))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException(SR.GetString(SR.ConfigInvalidBindingName,
bindingConfiguration,
ConfigurationHelpers.GetBindingsSectionPath(binding),
ConfigurationStrings.BindingConfiguration),
configurationElement.ElementInformation.Source,
configurationElement.ElementInformation.LineNumber));
}
}
}
}
ContextInformation IConfigurationContextProviderInternal.GetEvaluationContext()
{
return this.EvaluationContext;
}
/// <securitynote>
/// RequiresReview - the return value will be used for a security decision -- see comment in interface definition
/// </securitynote>
ContextInformation IConfigurationContextProviderInternal.GetOriginalEvaluationContext()
{
DiagnosticUtility.DebugAssert("Not implemented: IConfigurationContextProviderInternal.GetOriginalEvaluationContext");
return null;
}
}
}
</remove></clear></bindingcollectionelement></bindingcollectionelement></bindingcollectionelement></string,></string,></string,>

Related

.NET 5.0 SettingsSerializeAs.Binary obsolete

/// Serialization
/// Code 2012.05.23, [...] following Jani Giannoudis' examples
/// CodeProject Article "User Settings Applied",
/// http://www.codeproject.com/Articles/25829/User-Settings-Applied
/// </summary>
I'm using the above mentioned codeproject.com Code since a number of years successfully in different projects.
A few days ago, I converted one of those projects from .NET 4.x to .NET 6.0 and the unmodified code immediately stopped working (details below) for example in the following snippet:
// DataGridColumnSetting[] is based on System.Configuration.ApplicationSettingsBase
// https://learn.microsoft.com/en-us/dotnet/api/system.configuration.applicationsettingsbase?view=dotnet-plat-ext-6.0
private DataGridColumnSetting[] OriginalColumnSettings
{
get
{
return LoadValue(
Name,
typeof(DataGridColumnSetting[]),
SettingsSerializeAs.Binary,
null) as DataGridColumnSetting[];
}
}
Throwing a
System.NotSupportedException
HResult=0x80131515
Message=BinaryFormatter serialization is obsolete and should not be used. See https://aka.ms/binaryformatter for more information.
Source=System.Configuration.ConfigurationManager
StackTrace:
at System.Configuration.SettingsProperty..ctor(String name, Type propertyType, SettingsProvider provider, Boolean isReadOnly, Object defaultValue, SettingsSerializeAs serializeAs, SettingsAttributeDictionary attributes, Boolean throwOnErrorDeserializing, Boolean throwOnErrorSerializing)
at MyNamespace.Serialization.Setting.CreateSettingProperty(String name, Type type, SettingsSerializeAs serializeAs, Object defaultValue) in [...]MyNamespace\Serialization\Setting.cs:line 111
Since the very same code is working well in a .NET 4.8 project, I tried to find hints in the web and found
https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/5.0/binaryformatter-serialization-obsolete
(and a few others) also saying
Warning
"The BinaryFormatter type is dangerous and is not recommended for data processing. Applications should stop using BinaryFormatter as soon as possible, even if they believe the data they're processing to be trustworthy. BinaryFormatter is insecure and can't be made secure."
Actual Question:
Anyone else having the very same issue using the same code (from the above mentioned CodeProject Article "User Settings Applied").
(If not, I would start modifying (my personal flavor of) that code, and if successful post an answer to my question assuming others might hopefully benefit.)
Okay, apparently using JSON instead of Binary works as expected here in an http://www.codeproject.com/Articles/25829/User-Settings-Applied context (in .Net4.x as well as .Net 6).
The basic concept there is having a particular Serialization class for each UI Control one wants to handle. And only some of the article samples are using the deprecated SettingsSerializeAs.Binary, for example the one made for WPF DataGridcontrols. The concept modification that works for me is using (NuGet) Newtonsoft.Json for serialization there.
The typical pattern part where the article author is using SettingsSerializeAs as quoted in the question is now using SettingsSerializeAs.String instead of Binary:
private string OriginalColumnSettings
{
get
{
return LoadValue(
Name,
typeof(string),
SettingsSerializeAs.String,
defaultValue: null) as string;
}
}
Full real world (WPF) Sample for both .Net4.8 as well as .Net6:
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
namespace WhatEverNamespace.Serialization
{
/// <summary>
/// Serialization
/// Code 2012.05.23, [...] following Jani Giannoudis' examples
/// CodeProject Article "User Settings Applied",
/// http://www.codeproject.com/Articles/25829/User-Settings-Applied
/// </summary>
public class DataGridSetting : Setting
{
public static readonly DependencyProperty SettingProperty =
DependencyProperty.RegisterAttached(
"Setting",
typeof(string),
typeof(DataGridSetting),
new FrameworkPropertyMetadata(OnDataGridSettingChanged));
#region Fields
private static readonly Logger log = LogManager.GetCurrentClassLogger();
private readonly DataGrid dataGrid;
private readonly IList<DataGridColumn> dataGridColumns = new List<DataGridColumn>();
private bool isLoaded;
private readonly string name;
private bool useWidth = true;
private bool useDisplayIndex = true;
#endregion Fields
#region Constructors
public DataGridSetting(DataGrid dataGrid) :
this(dataGrid?.Name, dataGrid)
{
}
public DataGridSetting(string name, DataGrid dataGrid)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException(nameof(name));
this.name = name;
this.dataGrid = dataGrid ?? throw new ArgumentNullException(nameof(dataGrid));
}
#endregion Constructors
#region Properties
public string Name { get { return name; } }
public DataGrid DataGrid { get { return dataGrid; } }
public bool UseWidth
{
get { return useWidth; }
set { useWidth = value; }
}
public bool UseDisplayIndex
{
get { return useDisplayIndex; }
set { useDisplayIndex = value; }
}
public override bool HasChanged
{
get
{
var json = OriginalColumnSettings;
if (string.IsNullOrWhiteSpace(json))
return false;
var originalColumnSettings = JsonConvert.DeserializeObject<DataGridColumnSetting[]>(json);
DataGridColumnSetting[] columnSettings = ColumnSettings;
if (json.Length != columnSettings.Length)
return true;
for (int i = 0; i < originalColumnSettings.Length; i++)
{
if (!originalColumnSettings[i].Equals(columnSettings[i]))
return true;
}
return false;
}
}
private string OriginalColumnSettings
{
get
{
return LoadValue(
Name,
typeof(string),
SettingsSerializeAs.String,
defaultValue: null) as string;
}
}
private DataGridColumnSetting[] ColumnSettings
{
get
{
if (dataGrid?.Columns.Any() != true)
return null;
IList<DataGridColumnSetting> columnSettings =
new List<DataGridColumnSetting>(dataGrid.Columns.Count);
foreach (DataGridColumn dataGridColumn in dataGrid.Columns)
{
int index = dataGridColumns.IndexOf(dataGridColumn);
int displayIndex = dataGridColumn.DisplayIndex;
DataGridColumnSetting columnSetting = new DataGridColumnSetting
{
Index = index,
DisplayIndex = displayIndex,
Width = dataGridColumn.ActualWidth
};
columnSettings.Add(columnSetting);
}
return columnSettings.ToArray();
}
}
#endregion Properties
#region Methods
public static string GetSetting(DependencyObject dependencyObject)
{
return dependencyObject?.GetValue(SettingProperty) as string;
}
public static void SetSetting(DependencyObject dependencyObject, string settingKey)
{
dependencyObject?.SetValue(SettingProperty, settingKey);
}
public override void Load()
{
// Initialized event does not work since it's running too early in a WPF DataGrid
// ("dataGrid.Initialized += DataGridInitialized" in Jani's ListViewSettings.cs)
if (isLoaded == false)
SetupDataGridColumns();
try
{
DataGrid dataGrid = this.dataGrid;
if (dataGrid?.Columns.Any() != true)
return;
var json = OriginalColumnSettings;
var columnSettings = JsonConvert.DeserializeObject<DataGridColumnSetting[]>(json);
if (columnSettings?.Any() != true)
return;
for (int displayIndex = 0; displayIndex < columnSettings.Length; displayIndex++)
{
DataGridColumnSetting columnSetting = columnSettings[displayIndex];
if (columnSetting.Index < 0 || columnSetting.Index >= dataGridColumns.Count)
continue;
DataGridColumn dataGridColumn = dataGridColumns[columnSetting.Index];
if (useWidth)
dataGridColumn.Width = new DataGridLength(columnSetting.Width);
if (useDisplayIndex && columnSetting.Index != columnSetting.DisplayIndex)
dataGridColumn.DisplayIndex = columnSetting.DisplayIndex;
}
}
catch
{
if (ThrowOnErrorLoading)
throw;
}
}
public override void Save()
{
try
{
DataGridColumnSetting[] columnSettings = ColumnSettings;
if (columnSettings == null)
return;
var json = JsonConvert.SerializeObject(columnSettings);
SaveValue(
Name,
typeof(string),
SettingsSerializeAs.String,
json,
null);
}
catch
{
if (ThrowOnErrorSaving)
throw;
}
}
public override string ToString()
{
return string.Concat(name, " (DataGrid)");
}
private void SetupDataGridColumns()
{
dataGridColumns.Clear();
if (dataGrid == null)
return;
if (dataGrid.Columns.Count > 0)
isLoaded = true;
else
return;
for (int i = 0; i < dataGrid.Columns.Count; i++)
{
dataGridColumns.Add(dataGrid.Columns[i]);
}
}
private static void OnDataGridSettingChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
if (!(dependencyObject is DataGrid dataGrid))
{
log.Warn(CultureInfo.InvariantCulture,
"{0}.{1}(): invalid property attachment",
nameof(DataGridSetting),
nameof(OnDataGridSettingChanged));
return;
}
// search on the parent-tree for application settings
ApplicationSettings applicationSettings = FindParentSettings(dependencyObject);
if (applicationSettings == null)
{
log.Warn(CultureInfo.InvariantCulture,
"{0}.{1}(): missing application settings in parent hierarchy",
nameof(DataGridSetting),
nameof(OnDataGridSettingChanged));
return;
}
applicationSettings.Settings.Add(new DataGridSetting(dataGrid));
}
private static ApplicationSettings FindParentSettings(DependencyObject element)
{
while (element != null)
{
if (element.ReadLocalValue(
DependencyPropertySetting.ApplicationSettingsProperty) is ApplicationSettings applicationSettings)
return applicationSettings;
element = LogicalTreeHelper.GetParent(element);
}
return null;
}
#endregion Methods
}
}

CRM 2011 - C# PLUGIN

I have a CRM 2011 plugin using C#: Synchronus, Post-Operation and Not-Sandbox.
Whenever launched, the plugin works fine for the first time. But my problem is when I call the plugin the second time (with other GUID), the entity will have the first calling's values. So instead of having the new entity attributes that im just calling, im having the old entity's attributes (first call). Is there any solution to this problem?
Note that I have tried the Async mode and it worked fine, but I need to display error messages on the screen after calling a Webservice so I need it to be on Sync mode.
Plugin CLass:
namespace FNBChangeCustomerInfGroup
{
public abstract class Plugin : IPlugin
{
public IServiceProvider _serviceProvider;
public IOrganizationServiceFactory _organizationServiceFactory;
public IPluginExecutionContext _pluginExecutionContext;
public IOrganizationService _organizationService;
public ResourceManager _resourceManager;
public Lazy<Helper> _helper;
public IPluginExecutionContext PluginExecutionContext
{
get
{
if (_pluginExecutionContext == null)
{
_pluginExecutionContext = _serviceProvider.GetService(typeof(IPluginExecutionContext)) as IPluginExecutionContext;
if (_pluginExecutionContext == null)
{
throw new InvalidOperationException("Cannot get Execution Context");
}
}
return _pluginExecutionContext;
}
}
public IOrganizationServiceFactory OrganizationServiceFactory
{
get
{
if (_organizationServiceFactory == null)
{
_organizationServiceFactory = _serviceProvider.GetService(typeof(IOrganizationServiceFactory)) as IOrganizationServiceFactory;
if (_organizationServiceFactory == null)
{
throw new InvalidOperationException("Cannot get Service Factory");
}
}
return _organizationServiceFactory;
}
}
public IOrganizationService OrganizationService
{
get
{
if (_organizationService == null)
{
_organizationService = OrganizationServiceFactory.CreateOrganizationService(_pluginExecutionContext.UserId);
if (_organizationService == null)
{
throw new InvalidOperationException("Cannot get Organization Service");
}
}
return _organizationService;
}
}
protected virtual ResourceManager ResourceManager
{
get
{
if (_resourceManager == null)
{
_resourceManager = new ResourceManager(Constants.File_Resources, Assembly.GetExecutingAssembly());
if (_resourceManager == null)
{
throw new InvalidOperationException("Cannot access Resources file");
}
}
return _resourceManager;
}
}
protected Lazy<Helper> Helper
{
get
{
if (_helper == null || !_helper.IsValueCreated)
{
_helper = new Lazy<Helper>(() => new Helper(_organizationService));
}
return _helper;
}
}
public IExtensibleDataObject CheckType<ExtensibleDataObjectType>(string entityLogicalName) where ExtensibleDataObjectType : IExtensibleDataObject, new()
{
// Check if the input parameters property bag contains a target
// of the operation and that target is of type EntityReference.
if (PluginExecutionContext.InputParameters.Contains(Constants.InputParameter_Target) && PluginExecutionContext.InputParameters[Constants.InputParameter_Target] is ExtensibleDataObjectType)
{
// Obtain the target business entity from the input parameters.
IExtensibleDataObject entity = (PluginExecutionContext.InputParameters[Constants.InputParameter_Target]) as IExtensibleDataObject;
// Verify that the entity represents a risk carrier quote.
if (typeof(Entity).IsAssignableFrom(typeof(ExtensibleDataObjectType)))
{
if (!String.Equals(((Entity)entity).LogicalName, entityLogicalName)) { return null; }
}
else if (typeof(EntityReference).IsAssignableFrom(typeof(ExtensibleDataObjectType)))
{
if (!String.Equals(((EntityReference)entity).LogicalName, entityLogicalName)) { return null; }
}
return entity;
}
else
{
return null;
}
}
public virtual void Execute(IServiceProvider serviceProvider)
{
this._serviceProvider = serviceProvider;
}
}
}
This is what happens when a plugin class contains fields. Plugin classes are not allowed to be stateful, because they are instantiated once by the CRM platform and then reused. Therefore fields on these classes are not thread safe.
Check your CRMPluginBase class. Looking at method base.CheckType<Entity>() chances are this class has a private field holding an IPluginExecutionContext instance. Redesign your plugin base class and make shure it does not contain instance fields at all.

Get Instance using an existing delegate Factory based on Type (or Previous ViewModel)

Based on this page we've created a Wizard that has three steps. Everything works great, but we have one problem with the code given in the link, which is how it creates the next step instance (copy pasted from the link):
protected override IScreen DetermineNextItemToActivate(IList<IScreen> list, int lastIndex)
{
var theScreenThatJustClosed = list[lastIndex] as BaseViewModel;
var state = theScreenThatJustClosed.WorkflowState;
var nextScreenType = TransitionMap.GetNextScreenType(theScreenThatJustClosed);
var nextScreen = Activator.CreateInstance(nextScreenType, state);
return nextScreen as IScreen;
}
Currently, it looks like this in our project:
protected override IWizardScreen DetermineNextItemToActivate(IList<IWizardScreen> list, int lastIndex)
{
var theScreenThatJustClosed = list[lastIndex];
if (theScreenThatJustClosed == null) throw new Exception("Expecting a screen here!");
if (theScreenThatJustClosed.NextTransition == WizardTransition.Done)
{
TryClose(); // Close the entire Wizard
}
var state = theScreenThatJustClosed.WizardAggregateState;
var nextScreenType = _map.GetNextScreenType(theScreenThatJustClosed);
if (nextScreenType == null) return null;
// TODO: CreateInstance requires all constructors for each WizardStep, even if they aren't needed. This should be different!
var nextScreen = Activator.CreateInstance(nextScreenType, state, _applicationService, _wfdRegisterInstellingLookUp,
_adresService, _userService, _documentStore, _windowManager, _fileStore, _fileUploadService, _dialogService,
_eventAggregator, _aanstellingViewModelFactory);
return nextScreen as IWizardScreen;
}
As you can see, we have quite a few parameters we need in some steps. In step 1 we only need like two, but because of the Activator.CreateInstance(nextScreenType, state, ...); we still need to pass all of them.
What I'd like instead is to use a delegate Factory. We use them at more places in our project, and let AutoFac take care of the rest of the parameters. For each of the three steps we only need a delegate Factory that uses the state.
Because all three uses the same delegate Factory with just state, I've placed this Factory in their Base class:
public delegate WizardBaseViewModel<TViewModel> Factory(AggregateState state);
How I'd like to change the DetermineNextItemToActivate method:
protected override IWizardScreen DetermineNextItemToActivate(IList<IWizardScreen> list, int lastIndex)
{
var theScreenThatJustClosed = list[lastIndex];
if (theScreenThatJustClosed == null) throw new Exception("Expecting a screen here!");
if (theScreenThatJustClosed.NextTransition == WizardTransition.Done)
{
TryClose(); // Close the entire Wizard
}
return _map.GetNextScreenFactoryInstance(state);
}
But now I'm stuck at making the GetNextScreenFactoryInstance method:
public IWizardScreen GetNextScreenFactoryInstance(IWizardScreen screenThatClosed)
{
var state = screenThatClosed.WizardAggregateState;
// This is where I'm stuck. How do I get the instance using the Factory, when I only know the previous ViewModel
// ** Half-Pseudocode
var nextType = GetNextScreenType(screenThatClosed);
var viewModelFactory = get delegate factory based on type?;
var invokedInstance = viewModelFactory.Invoke(state);
// **
return invokedInstance as IWizardScreen;
}
Feel free to change the GetNextScreenFactoryInstance any way you'd like. As long as I can get the next Step-ViewModel based on the previous one in the map.
NOTE: Other relevant code, can be found in the link, but I'll post it here as well to keep it all together:
The WizardTransitionMap (only change is it not being a Singleton anymore, so we can instantiate a map outselves):
public class WizardTransitionMap : Dictionary<Type, Dictionary<WizardTransition, Type>>
{
public void Add<TIdentity, TResponse>(WizardTransition transition)
where TIdentity : IScreen
where TResponse : IScreen
{
if (!ContainsKey(typeof(TIdentity)))
{
Add(typeof(TIdentity), new Dictionary<WizardTransition, Type> { { transition, typeof(TResponse) } });
}
else
{
this[typeof(TIdentity)].Add(transition, typeof(TResponse));
}
}
public Type GetNextScreenType(IWizardScreen screenThatClosed)
{
var identity = screenThatClosed.GetType();
var transition = screenThatClosed.NextTransition;
if (!transition.HasValue) return null;
if (!ContainsKey(identity))
{
throw new InvalidOperationException(String.Format("There are no states transitions defined for state {0}", identity));
}
if (!this[identity].ContainsKey(transition.Value))
{
throw new InvalidOperationException(String.Format("There is no response setup for transition {0} from screen {1}", transition, identity));
}
return this[identity][transition.Value];
}
}
Our InitializeMap-method:
protected override void InitializeMap()
{
_map = new WizardTransitionMap();
_map.Add<ScreenOneViewModel, ScreenTwoViewModel>(WizardTransition.Next);
_map.Add<ScreenTwoViewModel, ScreenOneViewModel>(WizardTransition.Previous);
_map.Add<ScreenTwoViewModel, ScreenThreeViewModel>(WizardTransition.Next);
_map.Add<ScreenThreeViewModel, ScreenTwoViewModel>(WizardTransition.Previous);
_map.Add<ScreenThreeViewModel, ScreenThreeViewModel>(WizardTransition.Done);
}
We've changed the code:
The WizardTransitionMap now accepts Delegates. Also, instead of retrieving the type by the WizardTransition-enum value (Next, Previous, etc.), we now retrieve the Factory-invoke based on the next Type (so the inner Dictionary is reversed). So, this is our current WizardTransitionMap:
using System;
using System.Collections.Generic;
namespace NatWa.MidOffice.CustomControls.Wizard
{
public class WizardTransitionMap : Dictionary<Type, Dictionary<Type, Delegate>>
{
public void Add<TCurrentScreenType, TNextScreenType>(Delegate delegateFactory)
{
if (!ContainsKey(typeof(TCurrentScreenType)))
{
Add(typeof(TCurrentScreenType), new Dictionary<Type, Delegate> { { typeof(TNextScreenType), delegateFactory } });
}
else
{
this[typeof(TCurrentScreenType)].Add(typeof(TNextScreenType), delegateFactory);
}
}
public IWizardScreen GetNextScreen(IWizardScreen screenThatClosed)
{
var identity = screenThatClosed.GetType();
var state = screenThatClosed.State;
var transition = screenThatClosed.NextScreenType;
if (!ContainsKey(identity))
{
throw new InvalidOperationException(String.Format("There are no states transitions defined for state {0}", identity));
}
if (!this[identity].ContainsKey(transition))
{
throw new InvalidOperationException(String.Format("There is no response setup for transition {0} from screen {1}", transition, identity));
}
if (this[identity][transition] == null)
return null;
return (IWizardScreen)this[identity][transition].DynamicInvoke(state);
}
}
}
Our InitializeMap is now changed to this:
protected override void InitializeMap()
{
_map = new WizardTransitionMap();
_map.Add<ScreenOneViewModel, ScreenTwoViewModel>(_screenTwoFactory);
_map.Add<ScreenTwoViewModel, ScreenOneViewModel>(_screenOneFactory);
_map.Add<ScreenTwoViewModel, ScreenThreeViewModel>(_screenThreeFactory);
_map.Add<ScreenThreeViewModel, ScreenTwoViewModel>(_screenTwoFactory);
_map.Add<ScreenThreeViewModel, ScreenThreeViewModel>(null);
}
And our DetemineNexttemToActivate method to this:
protected override IWizardScreen DetermineNextItemToActivate(IList<IWizardScreen> list, int previousIndex)
{
var theScreenThatJustClosed = list[previousIndex];
if (theScreenThatJustClosed == null) throw new Exception("Expecting a screen here!");
var nextScreen = _map.GetNextScreen(theScreenThatJustClosed);
if (nextScreen == null)
{
TryClose();
return ActiveItem; // Can't return null here, because Caliburn's Conductor will automatically get into this method again with a retry
}
return nextScreen;
}
We also removed our entire WizardBaseViewModel and just let every Step-ViewModel implement the IWizardScreen:
public interface IWizardScreen : IScreen
{
AggregateState State { get; }
Type NextScreenType { get; }
void Next();
void Previous();
}
With the following implementation in our ScreenOneViewModel:
public AggregateState State { get { return _state; } }
public Type NextScreenType { get; private set; }
public void Next()
{
if (!IsValid()) return;
NextScreenType = typeof(ScreenTwoViewModel);
TryClose();
}
public void Previous()
{
throw new NotImplementedException(); // Isn't needed in first screen, because we have no previous
}
And the following implementation in our ScreenThreeViewModel:
public AggregateState State { get { return _state; } }
public Type NextScreenType { get; private set; }
public void Next()
{
NextScreenType = typeof(ScreenThreeViewModel); // Own type, because we have no next
TryClose();
}
public void Previous()
{
NextScreenType = typeof(ScreenTwoViewModel);
TryClose();
}
And each Step-ViewModel has its own delegate Factory, like this one for ScreenTwoViewModel:
public delegate ScreenTwoViewModel Factory(AggregateState state);

Using SharpSvn to retrieve log revisions got Disk issue

I'm workin on a wcf service to get some info of svn log.
My service method:
public List<SvnLogInfo> ViewLog(Executable ejecutable) {
Configuration config = m_context.Configuration.SingleOrDefault();
if (config != null) {
SvnClient svnClient = new SvnClient();
SvnRevisionRange svnRevisionRange = new SvnRevisionRange(ejecutable.SvnRevisionFrom, ejecutable.SvnRevisionTo);
SvnLogArgs args = new SvnLogArgs(svnRevisionRange);
Collection<SvnLogEventArgs> logCollection;
svnClient.GetLog(config.RepositoryPath, args, out logCollection);
List<SvnLogInfo> logInfo = new List<SvnLogInfo>();
foreach (SvnLogEventArgs log in logCollection) {
logInfo.Add((SvnLogInfo)log);
}
return logInfo;
}
return null;
}
[Serializable]
public class SvnLogInfo {
public SvnLogInfo() {
}
private string m_message;
public string Mensaje {
get { return m_message; }
set { m_message = value; }
}
private string m_author;
public string Autor {
get { return m_author; }
set { m_author = value; }
}
public static explicit operator SvnLogInfo(SvnLogEventArgs e) {
SvnLogInfo info = new SvnLogInfo();
info.Mensaje = e.LogMessage;
info.Autor = e.Author;
return info;
}
}
It works, but when excetuing this line:
svnClient.GetLog(config.RepositoryPath, args, out logCollection);
Throws me this error message:
There is no disk in drive G.
As I mention, I'm using SharpSvn library. Is there a way to solve this issues?. By the way, the variable config.RepositoryPath has this value "C:\Users\carlos.vega.CONTAPERU\Desktop\Solucion ContaNet v3 Espero Funcione"

Set Validation Message on Control Manually

I am trying to set the Validation Message manually without the common practice where you throw an exception.
I know I can manually change the state of the control as follows:
VisualStateManager.GoToState(this.TextBox, "InvalidFocused", true);
Now I just want to set the error message manually... Anyone know how?
I know this is a HACK but it's something I need at this point.
Any ideas???
Here is a solution....found this post.
public object Value
{
get { return (object)GetValue(ValueProperty); }
set
{
if (value.ToString() == "testing")
{
SetControlError(this, "This is an invalid value.");
}
else
{
ClearControlError(this);
SetValue(ValueProperty, value);
}
}
}
public void ClearControlError(Control control)
{
BindingExpression b = control.GetBindingExpression(Control.TagProperty);
if (b != null)
{
((ControlValidationHelper)b.DataItem).ThrowValidationError = false;
b.UpdateSource();
}
}
public void SetControlError(Control control, string errorMessage)
{
ControlValidationHelper validationHelper =
new ControlValidationHelper(errorMessage);
control.SetBinding(Control.TagProperty, new Binding("ValidationError")
{
Mode = BindingMode.TwoWay,
NotifyOnValidationError = true,
ValidatesOnExceptions = true,
UpdateSourceTrigger = UpdateSourceTrigger.Explicit,
Source = validationHelper
});
// this line throws a ValidationException with your custom error message;
// the control will catch this exception and switch to its "invalid" state
control.GetBindingExpression(Control.TagProperty).UpdateSource();
}
// Helper Class
using System.ComponentModel.DataAnnotations;
public class ControlValidationHelper
{
private string _message;
public ControlValidationHelper(string message)
{
if (message == null)
{
throw new ArgumentNullException("message");
}
_message = message;
ThrowValidationError = true;
}
public bool ThrowValidationError
{
get;
set;
}
public object ValidationError
{
get { return null; }
set
{
if (ThrowValidationError)
{
throw new ValidationException(_message);
}
}
}
}

Categories

Resources