We have a situation where the CrmServiceClient class cannot be instantiated, with an 'Object reference not set to an object' error coming from deep within the bowels of the constructor. I've also received a Collection was modified; enumeration operation may not execute error in a few situations.
This does not happen all the time, but we seem to be able to reproduce it when we trigger multiple requests very quickly.
We create the object as follows:
var ctx = new CrmServiceClient(ConfigurationManager.ConnectionStrings["Xrm"].ConnectionString);
The connection string is valid and we have set RequireNewInstance to true
We were originally using the ctx in a using block but we were advised that we shouldn't be disposing of the CrmServiceClient, so we've removed the using block, but this has not resolved the problem.
The stack trace is below - i've only pasted the relevant part. The stack leading up to this point can be any piece of code that attempts to connect to the CRM to retrieve data
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
at System.Collections.Generic.List`1.Enumerator.MoveNextRare()
at System.Collections.Generic.List`1.Enumerator.MoveNext()
at Microsoft.Xrm.Tooling.Connector.Utilities.GetOrgnameAndOnlineRegionFromServiceUri(Uri serviceUri, String& onlineRegion, String& organizationName, Boolean& isOnPrem)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.SetOrgnameAndOnlineRegion(Uri serviceUri)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(String serviceUri, String userName, String password, String domain, String homeRealmUri, String authType, String requireNewInstance, String clientId, String redirectUri, String tokenCacheStorePath, String loginPrompt, String certStoreName, String certThumbprint, String skipDiscovery)
at Microsoft.Xrm.Tooling.Connector.CrmConnection..ctor(IDictionary`2 connection)
at Microsoft.Xrm.Tooling.Connector.CrmConnection.Parse(String connectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient.ConnectToCrmWebService(String crmConnectionString)
at Microsoft.Xrm.Tooling.Connector.CrmServiceClient..ctor(String crmConnectionString)
I believe I've tracked down the issue. I used DotNetPeek to look at the underlying code that was failing. The static method GetOrgnameAndOnlineRegionFromServiceUriwas where the error was occurring.
I tracked it down to a static list (discoSvcs) that was being set to null before the method returns. Other threads that call this method are also trying to do things with this list. It ends up that there is a race condition where one thread could check to see if it isn't null.
The only way I can get around it now is making sure only one CrmServiceClient is being instantiated at any time, by using a lock. This isn't ideal but I am running out of time
Static list definition
namespace Microsoft.Xrm.Tooling.Connector
{
public class Utilities
{
private static CrmOnlineDiscoveryServers discoSvcs;
private static List<string> _autoRetryRetrieveEntityList;
private Utilities()
{
}
Problem Function
The static list variable is checked at the beginning of this function and if it is null, it is populated with some values. It is then used later in the method before being set to null in the finally block.
public static void GetOrgnameAndOnlineRegionFromServiceUri(
Uri serviceUri,
out string onlineRegion,
out string organizationName,
out bool isOnPrem)
{
isOnPrem = false;
onlineRegion = string.Empty;
organizationName = string.Empty;
if (serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS.COM") || serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.DE") || (serviceUri.Host.ToUpperInvariant().Contains("MICROSOFTDYNAMICS.US") || serviceUri.Host.ToUpperInvariant().Contains("DYNAMICS-INT.COM")))
{
if (Utilities.discoSvcs == null)
Utilities.discoSvcs = new CrmOnlineDiscoveryServers();
try
{
List<string> stringList = new List<string>((IEnumerable<string>) serviceUri.Host.Split(new string[1]
{
"."
}, StringSplitOptions.RemoveEmptyEntries));
organizationName = stringList[0];
stringList.RemoveAt(0);
StringBuilder stringBuilder = new StringBuilder();
foreach (string str in stringList)
{
if (!str.Equals("api"))
stringBuilder.AppendFormat("{0}.", (object) str);
}
string crmKey = stringBuilder.ToString().TrimEnd('.').TrimEnd('/');
stringBuilder.Clear();
if (!string.IsNullOrEmpty(crmKey))
{
CrmOnlineDiscoveryServer onlineDiscoveryServer = Utilities.discoSvcs.OSDPServers.Where<CrmOnlineDiscoveryServer>((Func<CrmOnlineDiscoveryServer, bool>) (w =>
{
if (w.DiscoveryServer != (Uri) null)
return w.DiscoveryServer.Host.Contains(crmKey);
return false;
})).FirstOrDefault<CrmOnlineDiscoveryServer>();
if (onlineDiscoveryServer != null && !string.IsNullOrEmpty(onlineDiscoveryServer.ShortName))
onlineRegion = onlineDiscoveryServer.ShortName;
}
isOnPrem = false;
}
finally
{
Utilities.discoSvcs.Dispose();
Utilities.discoSvcs = (CrmOnlineDiscoveryServers) null;
}
}
else
{
isOnPrem = true;
if (((IEnumerable<string>) serviceUri.Segments).Count<string>() < 2)
return;
organizationName = serviceUri.Segments[1].TrimEnd('/');
}
}
Related
So I have had an error "Object reference not set to an instance of an object".
Here is the area where the error is occurring from:
private async void Savebutton_click(object sender, RoutedEventArgs e)
{
string recipename = recipenametextbox.Text.ToString();
string recipemethod = methodtextbox.Text.ToString();
string recipeingredients = ingredientstextbox.Text.ToString();
//File names.
string recipenamefilename = recipename + "title.txt";
string recipemethodfilename = recipename + "method.txt";
string recipeingredientsfilename = recipename + "ingredients.txt";
await currentrecipe.folder.CreateFolderAsync(recipename);
await currentrecipe.folder.CreateFileAsync(recipenamefilename);
File.WriteAllText(recipenamefilename, recipename);
await currentrecipe.folder.CreateFileAsync(recipemethodfilename);
File.WriteAllText(recipemethodfilename, recipemethod);
await currentrecipe.folder.CreateFileAsync(recipeingredientsfilename);
File.WriteAllText(recipeingredientsfilename, recipeingredients);
//Clear currentrecipe ready for next recipe.
currentrecipe.folder = null;
currentrecipe.Picturefile = null;
currentrecipe.recipebackgroundcolourenabled = false;
}
I am presuming that it is something to do with initialising the currentrecipe variable's StorageFolder member (currentrecipe is a recipie varible). Also I don't think it is a duplicate of the NullReferanceException question, simply due to the fact that I know what the NullReferanceException is, and I know how to fix it in a way, but I do not know how to fix it for this particular NullReferanceException - for Storage Folders. Also the error happens at await currentrecipe.folder.CreateFolderAsync(recipename).
Here is my recipie class:
public sealed class recipie
{
public StorageFile Picturefile;
public StorageFolder folder;
public bool recipebackgroundcolourenabled;
}
As you say the error happens at
await currentrecipe.folder.CreateFolderAsync(recipename)
I'd first check that both currentrecipe and folder are initialized:
if (currentrecipe != null)
{
if (currentrecipe.folder != null)
{
await currentrecipe.folder.CreateFolderAsync(recipename)
}
else
{
Console.Write("currentrecipe.folder is null")
}
}
else
{
Console.Write("currentrecipe is null")
}
At least start with that, otherwise it could be that CreateFolderAsync returns null.
I'm just learning visual c# in visual studio
Ok, so I have a ton of data fields in a form, and then I want to write the handlers to all call one main method, update, which then updates a resultsEntry object, which encapsulates a bunch of uint variables with various names.
How do I write an update method to put in either the results object, or the update method that will take the name of the variable in resultsEntry as a string, and the integer to update it with, and then update that field.
Basically, I need to do a
resultsEntry.(inStringHere) = inValueHere;
where resultsEntry is the object being updated, the inStringHere specifies the field to be updated, and the inValueHere represents the integer value to assign to it.
Thanks!
Sam French
You have two challenges,
Setting a field/property in class using a string (the focus of your question). This will be accomplished using reflection.
Converting values to the type in your class (this may not be a problem for you, you may have 'typed' values. I have an ugly solution because this is not the main focus of your question.
Setting a property by name (see comments preceded with '**'):
static class Program
{
// A 'ResultEntry' type
public class ResultEntry
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
static void Main()
{
// some tuples Field1 = Property Name; Field2 = Raw Value (string)
List<Tuple<string, string>> rawEntries = new List<Tuple<string, string>>() {
new Tuple<string,string>("ID", "1")
, new Tuple<string, string>("FirstName", "George")
, new Tuple<string, string>("LastName", "Washington")
};
ResultEntry resultEntry = new ResultEntry();
// ** Get MemberInfo's for your ResultEntry. Do this once, not for each instance of ResultEntry!
MemberInfo[] members = resultEntry.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
// Iterate over input
foreach (var raw in rawEntries)
{
// find a MemberInfo (PropertyInfo) that matches your input 'PropertyName'
MemberInfo member = members.FirstOrDefault(m => m.MemberType == MemberTypes.Property && m.Name == raw.Item1);
if (member != null)
{
// if you input is typed you will not have to deal with
// conversion of the string to the actual type of the property
object val = raw.Item2.MyConverter(((PropertyInfo)member).PropertyType);
// ** set the value in 'ResultEntry'
((PropertyInfo)member).SetValue(resultEntry, val, null);
}
}
Console.WriteLine(string.Format("Result Entry: ID = {0}, FirstName = {1}, LastName = {2}", resultEntry.ID, resultEntry.FirstName, resultEntry.LastName));
Console.ReadLine();
}
}
If you need to deal with converting raw string input to type (e.g. string to int), then is just one strategy...
public static class Extensions
{
public static object MyConverter(this string rawValue, Type convertToMe)
{
// ugly, there are other strategies
object val;
if (convertToMe == typeof(Int32))
val = Convert.ToInt32(rawValue);
// ... add other type conversions
else
val = rawValue;
return val;
}
}
Hope this helps.
I'm trying to find a string from the List....seems like its not working and if I have just List<string> it does work.. meaning like the below code...
List<string> c = new List<string>();
c.Add("John Doe"));
c.Add("Erich Schulz"));
//I think the problem with the Criterion class?
here is my class structure:
public class Criterion
{
public Criterion(String propertyName, object value)
{
this.PropertyName = propertyName;
this.Value = value;
}
}
//here is the method...
public static List<Criterion> LoadNames()
{
List<Criterion> c = new List<Criterion>();
c.Add(new Criterion("Name1", "John Doe"));
c.Add(new Criterion("Name2", "Erich Schulz"));
return c;
}
here is the code I'm trying to make it work:
bool isExists = LoadNames.Any(s=> "Erich Schulz".Contains(s));
Error:
does not contain a definition for 'Any' and the best extension method overload 'System.Linq.Enumerable.Any<TSource>(System.Collections.Generic.IEnumerable<TSource>, System.Func<TSource,bool>)' has some invalid arguments
When you call .Contains(s), s isn't a string, it's Criterion. Use .Contains(s.propertyName).
bool isExists = LoadNames().Any(s=> "Erich Schulz".Contains(s.PropertyName));
Also you're using LoadNames as a method, you need to execute it first.
You're attempting to compare a string to a Criterion object, which just doesn't work.
Here is the fixed code:
bool isExists = LoadNames.Any(criterion => String.Equals(criterion.PropertyName, "Erich Schulz", StringComparison.OrdinalIgnoreCase));
I want to retrieve a specific record using IQueryable. But i get error 'No generic method 'Where' on type 'System.Linq.Queryable' is compatible with the supplied type arguments and arguments. No type arguments should be provided if the method is non-generic.'. I got the selected row id, but I cannot display it out. Here is my code.
internal static IQueryable GetRecordsFromPrimaryKeys(this IQueryable datasource, List<FilterDescriptor> primaryKeys)
{
IQueryable data = datasource;
ParameterExpression paramExp = null;
bool firstLoop = false;
System.Linq.Expressions.Expression predicate = null;
var RecordType = datasource.GetObjectType();
paramExp = RecordType.Parameter();
foreach (FilterDescriptor primaryKey in primaryKeys)
{
if (!(firstLoop))
{
predicate = data.Predicate(paramExp, primaryKey.ColumnName, primaryKey.Value, FilterType.Equals, false, RecordType);
firstLoop = true;
}
else
{
predicate = predicate.AndPredicate(data.Predicate(paramExp, primaryKey.ColumnName, primaryKey.Value, FilterType.Equals, false, RecordType));
}
}
if (paramExp != null && predicate != null)
{
var lambda = Expression.Lambda(predicate, paramExp);
data = data.Provider.CreateQuery(
Expression.Call(
typeof(Queryable),
"Where",
new Type[] { data.ElementType },
data.Expression,
lambda
)
);
}
return data;
}
My Code works well for IEnumerable/IQueryable/ICollection . But it throws the exception when i specify the class with the keyword virtual and type as ICollection. My code is
public class RoomType
{
public int ID { get; set; }
[MaxLength(10, ErrorMessage = "Room code cannot be longer than 10 characters.")]
public string Code { get; set; }
[MaxLength(50, ErrorMessage = "Room name cannot be longer than 50 characters.")]
public string Name { get; set; }
public virtual ICollection<RoomCategory> RoomCategories { get; set; }
}
Some random values gets appended to 'RecordType' while using the keyword 'virtual'. I think this leads to the exception. Still searching for the solution.
I don't know what is going wrong . Any suggestions welcome.
Thanks.
I just ran into a similar situation. The problem stems from the fact that in some cases you're dealing with the "proxy" not the actual entity. So, you want to make sure that RecordType matches data.ElementType.
try:
var recordType = datasource.GetObjectType();
// make sure we have the correct type (not the proxy)
if (recordType.BaseType.Name != "Object")
recordType = recordType.BaseType;
Or better yet, try:
var recordType = data.ElementType
Try to use typeof(Enumerable) instead of typeof(Queryable)
I have the following code.
XElement opCoOptOff = doc.Descendants(ns + "OpCoOptOff").FirstOrDefault();
String opCo = opCoOptOff.Element(ns + "strOpCo").Value;
Now if the element I return is null, I am getting a NullReferenceException since the XElement is null. So I changed it to the following.
String opCo = opCoOptOff.Element(ns + "strOpCo").Value;
if(opCoOptOff != null)
{
String opCo = opCoOptOff.Element(ns + "strOpCo").Value;
I am hoping there has to be a more elegant way to do this since this scenario comes up often and I would like to avoid doing this type of check every time there is an issue. Any assistance would be greatly appreciated
You can write an extension method and use it anywhere:
public static class XDocumentExtension
{
public static string GetSubElementValue(this XElement element, string item)
{
if(element != null && element.Value != null)
{
if (element.Element(item) != null)
{
return element.Element(item).Value;
}
}
return null;
}
public static XElement GetElement(this XElement element, string item)
{
if (element != null)
return element.Element(item);
return null;
}
public static XElement GetElement(this XDocument document, string item)
{
if (document != null)
return document.Descendants("item").FirstOrDefault();
return null;
}
}
Use it as :
String opCo = opCoOptOff.Element(ns + "strOpCo").GetSubElementValue(ns + "strOpCo");
Also you can add other extensions for your purpose.
Edit: I'd updated answer but if you read it carefully before I wrote you can add other extensions for your purpose. I wrote this because I guess you may be want to call on null objects Element, I don't know what's exact situation of yours but I add some code for more clarification, depend on your situation complete the XDocumentExtension class, and one note extension methods can work on null objects.
You can actually cast the XElement directly to a string:
http://msdn.microsoft.com/en-us/library/bb155263.aspx
so
String opCo = opCoOptOff.Element(ns + "strOpCo").Value;
could be
string opCo = (string) opCoOptOff.Element(ns + "strOpCo");