I have some code that reads in an xml file. However it is triggering an error at the 3rd IF statement:
if (xdoc.Root.Descendants("HOST").Descendants("Default")
.FirstOrDefault().Descendants("HostID")
.FirstOrDefault().Descendants("Deployment").Any())
Error:
System.NullReferenceException: Object reference not set to an instance of an object.
That is because in this particular file there is no [HOST] section.
I was assuming that on the first IF statement, if it didn't find any [HOST]section it would not go into the statement and therefore i should not get this error. Is there a way to check if a section exists first?
XDocument xdoc = XDocument.Load(myXmlFile);
if (xdoc.Root.Descendants("HOST").Any())
{
if (xdoc.Root.Descendants("HOST").Descendants("Default").Any())
{
if (xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault().Descendants("HostID").FirstOrDefault().Descendants("Deployment").Any())
{
if (xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault().Descendants("HostID").Any())
{
var hopsTempplateDeployment = xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault().Descendants("HostID").FirstOrDefault().Descendants("Deployment").FirstOrDefault();
deploymentKind = hopsTempplateDeployment.Attribute("DeploymentKind");
host = hopsTempplateDeployment.Attribute("HostName");
}
}
}
}
Within the body of this if block...
if (xdoc.Root.Descendants("HOST").Descendants("Default").Any())
{
if (xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault().Descendants("HostID").FirstOrDefault().Descendants("Deployment").Any())
{
if (xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault().Descendants("HostID").Any())
{
var hopsTempplateDeployment = xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault().Descendants("HostID").FirstOrDefault().Descendants("Deployment").FirstOrDefault();
deploymentKind = hopsTempplateDeployment.Attribute("DeploymentKind");
host = hopsTempplateDeployment.Attribute("HostName");
}
}
}
...you have established that the element <Root>/HOST/Default exists. You however don't know whether <Root>/HOST/Default/HostId/Deployment exists. If it doesn't you will get a NullReferenceException like the one you're experiencing due to the use of FirstOrDefault. It is generally recommended to use First in cases where you expect the elements to be present, which will give you at least a better error message.
If you expect the elements to be not present, a simple solution is to use the ?. along the respective LINQ2XML axis:
var hopsTemplateDeployment =
xdoc.Root.Descendants("HOST").Descendants("Default").FirstOrDefault()
?.Descendants("HostID").FirstOrDefault()
?.Descendants("Deployment").FirstOrDefault();
if (hopsTemplateDeployment != null)
{
deploymentKind = hopsTemplateDeployment.Attribute("DeploymentKind");
host = hopsTemplateDeployment.Attribute("HostName");
}
It will also save you the chain of nested if clauses.
Related
i have opened solidworks assembly (swDocumentTypes_e.swDocASSEMBLY) using C# and i have iterated through all the features in order to get all the Sketchs called 'ISO/XXX' under each part of the assembly, here is the code
public void openFile(string skeletonFilePath)
{
object[] Features = null;
int i = 0;
string FeatType = null;[1]
string FeatTypeName = null;
if (string.IsNullOrWhiteSpace(skeletonFilePath)) { return; }
ModelDoc2 model = _sldWorks.OpenDoc("C:PATH/fileName.SLDASM", (int)swDocumentTypes_e.swDocASSEMBLY);
Feature swFeat = default(Feature);
SelectionMgr swSelMgr = default(SelectionMgr);
swSelMgr = (SelectionMgr)model.SelectionManager;
swFeat = (Feature)model.FirstFeature();
while ((swFeat != null))
{
FeatType = swFeat.Name;
FeatTypeName = swFeat.GetTypeName2();
if ((FeatTypeName == "Reference")
{
Debug.Print(" Name of feature: " + swFeat.Name);
Debug.Print(" Type of feature: " + swFeat.GetTypeName2());
}
swFeat = (Feature)swFeat.GetNextFeature();
}
}
the problem:
each time i try to extract the items under the feature (of one part) i got an exception, i have to tried these ways:
swFeat.GetDefinition() // i've got null exception
swFeat.GetSpecificFeature2() // i've got dynamic value which i don't know the class i need to cast with
var childs = (Object[])swFeatSupport.GetChildren(); // i've got only to constraints under the part
example of project
Your code is only iterating over top level features. You can use IFeature::GetFirstSubFeature() and IFeature::GetNextSubFeature to get sub feature. Make this function recursive so it will iterate over all features, regardless of how many levels deep they are. Another layer you need to consider is the components - you need to iterate over components in an assembly first if you need feature data in the context of individual parts.
Here's an example from the Solidworks API documentation. Its poorly written (IMO) but it will guide you in the right direction.
Is there a way to prevent a $type property being added when I save my dynamic type values?
When I save this:
new Activity {
Name = "FormFieldDeleted",
Body = new {
MyDeletedFormField(),
MyCompleteForm()
}
}
I get this
<>f__AnonymousType1`2[[MyProject.Domains.Forms.Models.FormField, MyProject.Domains.Forms],[MyProject.Domains.Forms.Entities.FormRegistration, MyProject.Domains.Forms]], MyProject.Api.Forms
But when I try to fetch this saved entity, it crashes with the exception below. I know it's missing a project reference, but I really don't want to add that reference (I don't want to reference an API from a console app). It's better for me to just prevent the $type property.
/usr/local/share/dotnet/dotnet path/MyProject/MyProject/src/MyProject.Tasks.MapActivities/bin/Debug/netcoreapp3.1/MyProject.Tasks.MapActivities.dll
Unhandled exception. System.InvalidOperationException: Could not convert document 31317d58-db9e-4f60-8dee-b8593f3e06c0 to entity of type MyProject.Domains.Core.Entities.Activity
---> Newtonsoft.Json.JsonSerializationException: Error resolving type specified in JSON '<>f__AnonymousType1`2[[MyProject.Domains.Forms.Models.FormField, MyProject.Domains.Forms],[MyProject.Domains.Forms.Entities.FormRegistration, MyProject.Domains.Forms]], MyProject.Api.Forms'. Path 'Body.$type'.
---> Newtonsoft.Json.JsonSerializationException: Could not load assembly 'MyProject.Api.Forms'
....
Yes, there is a way.
You can customize the way serialization works using the following code:
store.Conventions.CustomizeJsonSerializer = serializer =>
{
serializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
};
As an example, take a look at the code here : https://dotnetfiddle.net/voJ7US
If you execute the code at the dotnetfiddle, you can see the results here: http://live-test.ravendb.net/studio/index.html#databases/documents?collection=Activities&database=UniqueTestDB
For RavenDB 5 and higher it changed a bit.
var store = DocumentStore
{
Urls = new[] { "your-endpoint" },
Conventions = new DocumentConventions
{
Serialization = new NewtonsoftJsonSerializationConventions
{
CustomizeJsonSerializer = serializer =>
{
serializer.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.None;
}
}
}
}.Initialize();
See https://ravendb.net/docs/article-page/5.0/file-header/migration/client-api/conventions for more information.
I want the ability to reset a single user setting easily to its default value.
I've written an extension like so:
public static void sReset(this Properties.Settings set, string key = "")
{
if (key == "")
{
set.Reset();
return;
}
Console.WriteLine("Reset '" + key + "' to: " + set.Properties[key].DefaultValue);
set.PropertyValues[key].PropertyValue = set.PropertyValues[key].Property.DefaultValue;
}
And this works fine for primitive types.
But now I want to apply that to a stringCollection, and it fails:
An unhandled exception of type 'System.InvalidCastException' occurred
in myApp.exe
Additional information: Unable to cast object of type 'System.String'
to type 'System.Collections.Specialized.StringCollection'.
This is because these collection type default values (Stored serialized as XML) are returned as strings:
set.Properties[key].DefaultValue.GetType() returns System.String
I can see in the settings designer that usually, it just casts the value to StringCollection:
public global::System.Collections.Specialized.StringCollection settingsName {
get {
return ((global::System.Collections.Specialized.StringCollection)(this["settingsName"]));
}
set {
this["settingsName"] = value;
}
}
But that fails after assigning the DefaultValue, with the above error message.
I tried casting the XML String before assigning, but of course that failed there, too.
How is an XML String like this converted before being assigned to the settings property?
What do I need to do to make this work?
Nobody?
That sucks, I would've thought there was a more elegant solution...
So I'm using this now:
Check if the Type of the setting is StringCollection
Read out XML Elements at "ArrayOfString/string"
... <-- wouldn't let me format code as code without an additional paragraph here. What the hell?
public static void sReset(this Properties.Settings set, string key = "")
{
if (key == "")
{
set.Reset();
return;
}
if (set.PropertyValues[key].Property.PropertyType == typeof(StringCollection))
{
string tvs = (string)set.PropertyValues[key].Property.DefaultValue;
set.PropertyValues[key].PropertyValue = tvs.XmlToStringCollection();
return;
}
set.PropertyValues[key].PropertyValue = set.PropertyValues[key].Property.DefaultValue;
}
public static StringCollection XmlToStringCollection(this string str)
{
StringCollection ret = new StringCollection();
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(str);
XmlNodeList terms = xmlDoc.SelectNodes("ArrayOfString/string");
foreach (XmlElement s in terms)
{
if (s.InnerXml != "")
{
Console.WriteLine("Found: " + s.InnerXml);
ret.Add(s.InnerXml);
}
}
return ret;
}
since the XML looks like this:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>first string</string>
<string>second string</string>
<string>...</string>
</ArrayOfString>
...Which is a shame, it's damn ugly and limited:
You'd have to do the same for any kind of XML serialized type
Really, what I'd like is a way to get the default value the same way VS does.
I can't imagine it could be as hacky as this, could it?
I realize this is an old question, but if anyone else lands here like I did, the OP's solution works. However, to answer OP's final question, I suspect Microsoft is using the XmlSerializer class, something like this extension method I came up with, though I also couldn't find a simple method call to do it for me:
public static StringCollection ToStringCollection(this string str)
{
// Create an instance of the XmlSerializer.
XmlSerializer serializer =
new XmlSerializer(typeof(StringCollection));
// Declare an object variable of the type to be deserialized.
StringCollection sc;
using (Stream reader = new MemoryStream(Encoding.Unicode.GetBytes(str)))
{
// Call the Deserialize method to restore the object's state.
sc = (StringCollection)serializer.Deserialize(reader);
}
return sc;
}
The above is based upon example code from https://learn.microsoft.com/en-us/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=net-6.0
I need to check if a element exists basically and if it does I want to open a url then back to the original page and then continue writing as it was. I tried a few approaches but they kept giving throwing exceptions. I added comments to the lines in question. I just cant figure out how to implement it.
foreach (string line in File.ReadLines(#"C:\\tumblrextract\\in7.txt"))
{
if (line.Contains("#"))
{
searchEmail.SendKeys(line);
submitButton.Click();
var result = driver.FindElement(By.ClassName("invite_someone_success")).Text;
if (driver.FindElements(By.ClassName("invite_someone_failure")).Count != 0)
// If invite_someone_failure exists open this url
driver.Url = "https://www.tumblr.com/lookup";
else
// Then back to following page and continue searchEmail.SendKeys(line); submitButton.Click(); write loop
driver.Url = "https://www.tumblr.com/following";
using (StreamWriter writer = File.AppendText("C:\\tumblrextract\\out7.txt"))
{
writer.WriteLine(result + ":" + line);
}
}
}
What is the exception you are getting? probably it may be Null reference exception. Please consider adding Null check in your code for the following
if(By.ClassName("invite_someone_success") != null){
var result = driver.FindElement(By.ClassName("invite_someone_success")).Text;
}
Above is not verified/exact code, just a pseudo code
you are using selenium and your might throw exceptions in some lines of code you have there - also take in consideration that i don't know tumblr website and it's html structure.
But first:
You're in a foreach loop and everytime you load at least once a page, all your elements will Stale, so this lines:
var searchEmail = driver.FindElement(By.Name("follow_this"));
var submitButton = driver.FindElement(By.Name("submit"));
will probably Stale in the next execution. (ElementStaleException).
Paste them too after:
driver.Url = "https://www.tumblr.com/following";
Second:
when using FindElement method you have to make sure the element exists or an ElementNotFoundException will also be thrown.
var result = driver.FindElement(By.ClassName("invite_someone_success")).Text;
var isThere = driver.FindElements(By.ClassName("invite_someone_failure"));
the dotNet selenium client have a static (i believe) class to help with that it's the ExpectedCondition
that you can use to check if an element is present before trying to read it's text..
I Invite you to understand how selenium works, specially StaleElementReferenceException.
Have fun.
In Revit 2013 I have tool that I'm making that copies dimensions from one drafting view to another. I've got it to properly create a new version of a dimension including the Curve, DimensionType, and References but I'm having trouble with the properties Above, Below, Prefix, and Suffix. They copy just fine if at least one of them has a value. However, if none of them have a value then it will throw an AccessViolationException when I try to access them. I have tried to catch that exception but it bubbles up and it crashes Revit (I'm assuming it's caused by native code that fails).
How can I check to see if these properties have any value when I do my copying without triggering this AccessViolationException?
Autodesk Discussion Group Question
The DimensionData class is my own used for storing the dimension information so that it can be used to create the dimension in a separate document.
private IEnumerable<DimensionData> GetDimensionDataSet(Document document,
View view)
{
if (document == null)
throw new ArgumentNullException("document");
if (view == null)
throw new ArgumentNullException("view");
List<DimensionData> dimensionDataSet = new List<DimensionData>();
FilteredElementCollector dimensionCollector =
new FilteredElementCollector(document, view.Id);
dimensionCollector.OfClass(typeof(Dimension));
foreach (Dimension oldDimension in dimensionCollector)
{
Line oldDimensionLine = (Line)oldDimension.Curve;
string dimensionTypeName = oldDimension.DimensionType.Name;
List<ElementId> oldReferences = new List<ElementId>();
foreach (Reference oldReference in oldDimension.References)
oldReferences.Add(oldReference.ElementId);
DimensionData dimensionData;
try
{
string prefix = oldDimension.Prefix;
dimensionData = new DimensionData(oldDimensionLine,
oldReferences,
dimensionTypeName,
prefix,
oldDimension.Suffix,
oldDimension.Above,
oldDimension.Below);
}
catch (AccessViolationException)
{
dimensionData = new DimensionData(oldDimensionLine,
oldReferences, dimensionTypeName);
}
dimensionDataSet.Add(dimensionData);
}
return dimensionDataSet;
}
Regarding transactions: As far as I'm aware, you are only required to be inside a transaction when you are making any sort of CHANGE (modifications, deletions, additions). If all you are doing is collecting dimension information, you would not need a transaction, but when you use that information to create new dimensions in another document, that code would have to be inside a transaction. I have had a number of programs under development which did not yet modify the document but simply collected parameter settings and posted them to a TaskDialog.Show(). These programs worked fine, and I don't see anything in your code that actually modifies your model, so that doesn't seem to be your issue.
It seems like I bug.
Can you post the issue to the ADN Support?
The solution I can suggest is to use Parameters of the Dimension element instead of Dimension class properties.
For example, you can get Suffix and Prefix by following code
var suffixParameter =
oldDimension.get_Parameter(BuiltInParameter.SPOT_SLOPE_SUFFIX);
string suffix = null;
if (suffixParameter != null)
{
suffix = suffixParameter.AsString();
}
var prefixParameter =
oldDimension.get_Parameter(BuiltInParameter.SPOT_SLOPE_PREFIX);
string prefix = null;
if (prefixParameter != null)
{
prefix = prefixParameter.AsString();
}
Unfortunatelly, I don't tell you how to get Above and Below Properties via parameters, because I don't have a project to test. But you can easily determine parameters using BuiltInParameter Checker
Hope it helps.