I have implemented a computed field index in Sitecore 7.2. However, the index manager is broken now and I get the following message
Invalid cast from 'System.String' to 'Sitecore.ContentSearch.ProviderIndexConfiguration'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidCastException: Invalid cast from 'System.String' to 'Sitecore.ContentSearch.ProviderIndexConfiguration'.
I have implemented the following class for my computed field:
namespace Computed.Search
{
public class OfficeLocationComputedField : IComputedIndexField
{
public string FieldName { get; set; }
public string ReturnType { get; set; }
public object ComputeFieldValue(IIndexable indexable)
{
Assert.ArgumentNotNull(indexable, nameof(indexable));
try
{
var result = new List<string>();
var indexableItem = indexable as SitecoreIndexableItem;
if (indexableItem == null)
return null;
var item = (Item) indexableItem;
// Treelist fields map to the MultilistField type as per ~/App_Config/FieldTypes.config
MultilistField field = item?.Fields["officelocation"];
if (field == null)
return null;
var items = field.GetItems();
if (items == null || items.Length == 0)
return result;
foreach (var locationItem in items)
{
//result.Add(locationItem.Name); // if you want the name of the item
result.Add(locationItem.DisplayName); // if you want the display name of the item
//result.Add(locationItem["Title"]); // if you want the value of a field on the item
}
return result;
}
catch (Exception exception)
{
Log.Error($"An Error occured in custom computed index. {exception.Message}", exception);
}
return null;
}
}
}
And the configuration file is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<contentSearch>
<indexConfigurations>
<defaultLuceneIndexConfiguration>
<fields hint="raw:AddComputedIndexField">
<field fieldName="officelocation" storageType="YES" indexType="TOKENIZED">Computed.Search.OfficeLocationComputedField, Computed</field>
</fields>
</defaultLuceneIndexConfiguration>
</indexConfigurations>
</contentSearch>
</sitecore>
</configuration>
I don't know what mistake I am making or what else I need to change?
The Sitecore Invalid cast from 'System.String' to ... exception in 90% cases is cause by the configuration mistakes.
In your case Sitecore tries to cast string to ProviderIndexConfiguration. It's LuceneIndexConfiguration which inherits from ProviderIndexConfiguration.
It looks like Sitecore cannot match you patch file content with default Lucene index configuration.
Make sure that your patch file name is alphabetically after Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config.
It the problem persists, add type attribute to defaultLuceneIndexConfiguration tag and set it to type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider":
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<contentSearch>
<indexConfigurations>
<defaultLuceneIndexConfiguration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">
<fields hint="raw:AddComputedIndexField">
<field fieldName="officelocation" storageType="YES" indexType="TOKENIZED">Computed.Search.OfficeLocationComputedField, Computed</field>
</fields>
</defaultLuceneIndexConfiguration>
</indexConfigurations>
</contentSearch>
</sitecore>
</configuration>
The older patch file that I had created and was alphabetically before the Sitecore.ContentSearch.Lucene.DefaultIndexConfiguration.config was still in the Website\App_Config\Include folder. I forgot to remove it. Removing that old file fixed the problem. Everything is working now.
Related
I'm developing a hobby project that communicates with external hardware (a robot), and am stuck with a few compiler errors that I can’t resolve.
Now before a mod closes this because other questions with this error have been asked, I have read numerous posts about other users CS1061 errors (e.g. Error CS1061 'object' does not contain a definition for and no accessible extension method accepting a first argument of type 'object' could be found), as well as relevant support documents (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-messages/cs1061?f1url=%3FappId%3Droslyn%26k%3Dk(CS1061)). However, the level of expertise/experience in these previous questions is beyond my ability to comprehend and apply to my specific problem (or maybe I'm just daft and can't figure this out). I am in need of specific guidance explaining how to address my particular problem.
Ok, getting down to it. The errors are:
error CS1061: 'object' does not contain a definition for 'Connection' and no accessible extension method 'Connection' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
error CS1061: 'object' does not contain a definition for 'Devices' and no accessible extension method 'Devices' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
and occur on lines 7, 9, 15, 30, and 32 in the 1st code block below.
They seem to be related to data in the Xml (Connection and Devices) not being correctly recognized/stored in the object "value" (or value2). For background, the Xml file (3rd code block below) is read into a dictionary using the XmlSettings class, which I've provided in the 2nd code block below.
XmlSettings xmlSettings;
xmlSettings = new XmlSettings();
xmlSettings.Load();
if (xmlSettings.TryGetValue("Cambus", out var value))
{
string text;
text = this.CameraConnection ?? value.Connection;
this.systemConfiguration = new List<RaspDeviceConfiguration>();
if (string.Empty.Equals(value.Devices))
{
return;
}
try
{
foreach (dynamic item in (IEnumerable<object>)value.Devices)
{
Type type;
type = Type.GetType((string)item.Impl, throwOnError: true);
if (typeof(IRaspComponent).IsAssignableFrom(type))
{
this.systemConfiguration.Add(new RaspDeviceConfiguration(type, item.Role, text, item.Address, item.Configuration));
}
}
}
catch (Exception)
{
this.systemConfiguration = null;
throw;
}
}
if (xmlSettings.TryGetValue("Mountarm", out var value2) && ((!string.IsNullOrEmpty(value2.Connection)) ? true : false))
{
this.ServoConnection = value2.Connection;
}
XmlSettings is a public class that loads an Xml file with various hardware settings. TryGetValue is a function within the XmlSettings class, and value is of type object.
Below is the XmlSettings code:
public class XmlSettings
{
private readonly ILog log = LogManager.GetLogger(typeof(XmlSettings));
private ExpandoObject expandobj;
public void Load()
{
string path = Path.Combine(Path.GetDirectoryName(typeof(XmlSettings).Assembly.Location), "RaspCamModuleSettings.xml");
Load(path);
}
public void Load(string path)
{
log.DebugFormat("Loading settings from {0}", path);
expandobj = _getExpandobjFromXml(path);
}
public bool TryGetValue(string property, out object value)
{
if (expandobj != null)
{
return ((IDictionary<string, object>)expandobj).TryGetValue(property, out value);
}
value = null;
return false;
}
private static dynamic _getExpandobjFromXml(string file, XElement node = null)
{
if (string.IsNullOrWhiteSpace(file) && node == null)
{
return null;
}
node = ((!string.IsNullOrWhiteSpace(file)) ? XDocument.Load(file).Root : node);
IDictionary<string, object> dictionary = new ExpandoObject();
PluralizationService pluralizationService = PluralizationService.CreateService(CultureInfo.CreateSpecificCulture("en-us"));
foreach (XElement gn in node.Elements())
{
bool flag = gn.HasElements && ((gn.Elements().Count() > 1 && gn.Elements().All((XElement e) => e.Name.LocalName.ToLower() == gn.Elements().First().Name.LocalName)) || gn.Name.LocalName.ToLower() == pluralizationService.Pluralize(gn.Elements().First().Name.LocalName).ToLower());
List<XElement> obj = (flag ? gn.Elements().ToList() : new List<XElement> { gn });
List<object> list = new List<object>();
foreach (XElement item in obj)
{
list.Add(item.HasElements ? _getExpandobjFromXml(null, item) : _extractNodeValue(item));
}
dictionary[gn.Name.LocalName] = (flag ? list : list.FirstOrDefault());
}
return dictionary;
}
private static object _extractNodeValue(XElement node)
{
object obj = node.Value.Trim();
XAttribute xAttribute = node.Attribute("clr-type");
if (xAttribute != null)
{
string text = xAttribute.Value.Trim();
if (!text.Contains('.'))
{
text = "System." + text;
}
Type type = Type.GetType(text, throwOnError: true, ignoreCase: true);
obj = Convert.ChangeType(obj, type);
}
return obj;
}
}
Lastly, to help contextualize, the Xml settings file (RaspCamModuleSettings.xml):
<?xml version="1.0" encoding="utf-8" ?>
<DeviceConfig>
<Cambus>
<Connection></Connection>
<Devices>
<Device>
<Role>camera1</Role>
<Address clr-type="int32">15</Address>
<Impl>Rasp.Core.RaspCamComponent,Rasp.Core</Impl>
<Configuration>
<![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<CamConfigurations>
<CamConfiguration TargetProductNumber="711">
<Diagflags0Mask>2024</Diagflags0Mask>
<OptionToggles>0</OptionToggles>
</CamConfiguration>
</CamConfigurations>
]]>
</Configuration>
</Device>
<Device>
<Role>camera2</Role>
<Address clr-type="int32">18</Address>
<Impl>Rasp.Core.RaspCamComponent,Rasp.Core</Impl>
<Configuration>
<![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<CamConfigurations>
<CamConfiguration TargetProductNumber="711">
<Diagflags0Mask>2024</Diagflags0Mask>
<OptionToggles>0</OptionToggles>
</CamConfiguration>
</CamConfigurations>
]]>
</Configuration>
</Device>
<Device>
<Role>camera3</Role>
<Address clr-type="int32">23</Address>
<Impl>Rasp.Core.RaspCamComponent,Rasp.Core</Impl>
<Configuration>
<![CDATA[
<?xml version="1.0" encoding="utf-8" ?>
<CamConfigurations>
<CamConfiguration TargetProductNumber="711">
<Diagflags0Mask>2024</Diagflags0Mask>
<OptionToggles>0</OptionToggles>
</CamConfiguration>
</CamConfigurations>
]]>
</Configuration>
</Device>
</Devices>
</Cambus>
<ProcedureBasePath></ProcedureBasePath>
</DeviceConfig>
This is a compiler error. The compiler has no way of knowing the structure of your XML document. This has to be done at run time.
You can have the compiler generate code to do it at run time by using the dynamic compile-time type. Using var in the fourth line of your code sample causes the compile-time type of the variable to be object. Instead, try
if (xmlSettings.TryGetValue("Cambus", out dynamic value))
//...
That will fix the compiler error.
Incidentally, if you declare expandobj as dynamic instead of ExpandoObject, you can use expandobj.Cambus instead of ((IDictionary<string, object>)expandobj).TryGetValue("Cambus", out value). However, that will throw if "Cambus" is missing, so you might want to stick with TryGetValue. If you do, though, you'll still want to change the key line to ((IDictionary<string, dynamic>)expandobj).TryGetValue("Cambus", out value).
I've added a ComputedIndexFields.config files with the following code:
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<contentSearch>
<indexConfigurations>
<defaultIndexConfiguration>
<fields hint="raw:AddComputedIndexField">
<field fieldName="AppliedThemes" storageType="yes" indexType="TOKENIZED">be.extensions.AppliedThemes, be.extensions</field>
</fields>
</defaultIndexConfiguration>
</configuration>
</contentSearch>
</sitecore>
</configuration>
I also added a class in said assemlby:
namespace be.extensions
{
class AppliedThemes : IComputedIndexField
{
public string FieldName { get; set; }
public string ReturnType { get; set; }
public object ComputeFieldValue(IIndexable indexable)
{
Item item = indexable as SitecoreIndexableItem;
if (item == null)
return null;
var themes = item["Themes"];
if (themes == null)
return null;
// TODO
}
}
}
I wanted to test the little bit of code i had already written. So i added a breakpoint at the first line of the "ComputeFieldValue(IIndexable indexable)" method and fired up the website ( while debugging ).
I changed several items, saved them en then rebuild the index tree but my breakpoint is never hit.
The class is located in a different project and build into a .dll with the assemblyname "be.extensions"
I'm using sitecore 8 update 2.
Does anyone know what i did wrong or why this code wouldn't be reached ?
( Like is this code send to some Lucene workflow that i simply can not debug )
Your configuration is likely not being patched in due to a change Sitecore made to the structure of the Include file. Namely, the defaultIndexConfiguration node was changed to defaultLuceneIndexConfiguration along with a new type attribute. You can verify that your computed field is being patched correctly using the /sitecore/admin/showconfig.aspx utility page. Also, please note that the storageType and indextype for each computed index field is now defined in the <fieldMap><fieldNames> section, not where you have it now.
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<sitecore>
<contentSearch>
<indexConfigurations>
<defaultLuceneIndexConfiguration type="Sitecore.ContentSearch.LuceneProvider.LuceneIndexConfiguration, Sitecore.ContentSearch.LuceneProvider">
<fields hint="raw:AddComputedIndexField">
<field fieldName="yourname">be.extensions.AppliedThemes, be.extensions</field>
</fields>
</defaultLuceneIndexConfiguration>
</indexConfigurations>
</contentSearch>
</sitecore>
</configuration>
In my ASP MVC Application I am populating the content present in a view based on data from XML files.
What my question is, am I doing this the best way? Surely there has got to be a more efficient and easier way to do what I'm doing here.
Here is an example of the markup in my XML file:
<?xml version="1.0" encoding="utf-8" ?>
<Content>
<!-- P1: Customer details -->
<ContentItem>
<key>Header_CancelImg</key>
<value>~/Content/mainpage/images/close.gif</value>
</ContentItem>
<ContentItem>
<key>Header_CancelText</key>
<value>Cancel this application</value>
</ContentItem>
So, I am deserialzing the contents of this XML file like so:
using (MemoryStream ms = new MemoryStream(System.IO.File.ReadAllBytes(path))) {
XmlSerializer serializer = new XmlSerializer(typeof(Content));
pageContent = serializer.Deserialize(ms) as Content;
}
All good. Now, based on this, what is the best way I can populate my view based on this content? Let me show you what I mean, and how I'm doing it now (very horribly):
#model <project.Models.Content> // This content object contains Content object where the deserializer is present as shown above
#foreach (var contentItem in Model.Item2.contentItemList)
{
#if(contentItem.key == "Header_CancelImg")
{
<img src="#Url.Content(contentItem.value)">
continue;
}
#if(contentItem.key == "Header_CancelText")
{
<p>#contentItem.value</p>
continue;
}
} // and so on
Is there a more easier way I can do this?
Thanks
If you gave your Content class a default property, you could access the data from your model by referencing the key names without having to iterate over all the different possible keys. I have shown a private dictionary property which is lazily initialized on the first hit.
public class Content
{
private Dictionary<string, string> contentItems;
public string this[string key]
{
if (contentItems == null)
{
contentItems = contentItemList.ToDictionary(i => i.Key, i => i.Value);
}
if (contentItems.ContainsKey(key))
{
return contentItems[key];
}
return string.Empty;
}
//other properties
}
Then your razor code could be like this:
#model project.Models.Content
<img src="#Url.Content(Model["Header_CancelImg"])">
<p>#Model["Header_CancelText"]</p>
I followed the steps here to create a new custom rule and add it to the ruleset in VSStudio 2013:
http://blog.tatham.oddie.com.au/2010/01/06/custom-code-analysis-rules-in-vs2010-and-how-to-make-them-run-in-fxcop-and-vs2008-too/
However, despite all my efforts, the custom rule does not show up in the ruleset file.
If I add the rule in the FXCop Editor, it shows up and analyzes the target project correctly.
This is the Rule File, which is an embedded resource in the project:
<?xml version="1.0" encoding="utf-8" ?>
<Rules FriendlyName="PSI Custom FxCop Rules">
<Rule TypeName="EnforceHungarianNotation" Category="PSIRules" CheckId="CR0001">
<Name>Enforce Hungarian Notation</Name>
<Description>Checks fields for compliance with Hungarian notation.</Description>
<Resolution>Field {0} is not in Hungarian notation. Field name should be prefixed with '{1}'.</Resolution>
<MessageLevel Certainty="100">Error</MessageLevel>
<FixCategories>Breaking</FixCategories>
<Url />
<Owner />
<Email />
</Rule>
</Rules>
This is my RuleSet:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="New Rule Set" Description=" " ToolsVersion="10.0">
<RuleHintPaths>
<Path>C:\App\PSI\Development\Source\JHA.ProfitStars.PSI\JHA.ProfitStars
.PSI.FxCop\bin\Debug</Path>
</RuleHintPaths>
</RuleSet>
I even tried adding the line below, but now it shows an Unknown rule in the ruleset:
<Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis"
RuleNamespace="Microsoft.Rules.Managed">
<Rule Id="CR0001" Action="Error" />
</Rules>
Could someone please help me understand what I am doing wrong here?
Edited:
BaseClass for rules:
internal abstract class BaseFxCopRule : BaseIntrospectionRule
{
protected BaseFxCopRule(string ruleName)
: base(ruleName, "JHA.ProfitStars.PSI.FxCop.Rules", typeof(BaseFxCopRule).Assembly)
{ }
}
Rules Class:
internal sealed class EnforceHungarianNotation : BaseFxCopRule
{
public EnforceHungarianNotation()
: base("EnforceHungarianNotation")
{
}
public override TargetVisibilities TargetVisibility
{
get
{
return TargetVisibilities.NotExternallyVisible;
}
}
public override ProblemCollection Check(Member member)
{
Field field = member as Field;
if (field == null)
{
// This rule only applies to fields.
// Return a null ProblemCollection so no violations are reported for this member.
return null;
}
if (field.IsStatic)
{
CheckFieldName(field, s_staticFieldPrefix);
}
else
{
CheckFieldName(field, s_nonStaticFieldPrefix);
}
// By default the Problems collection is empty so no violations will be reported
// unless CheckFieldName found and added a problem.
return Problems;
}
private const string s_staticFieldPrefix = "s_";
private const string s_nonStaticFieldPrefix = "m_";
private void CheckFieldName(Field field, string expectedPrefix)
{
if (!field.Name.Name.StartsWith(expectedPrefix, StringComparison.Ordinal))
{
Resolution resolution = GetResolution(
field, // Field {0} is not in Hungarian notation.
expectedPrefix // Field name should be prefixed with {1}.
);
Problem problem = new Problem(resolution);
Problems.Add(problem);
}
}
}
Looks like your path is kind of shaky, remove some spacing and unwanted characters:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="New Rule Set" Description=" " ToolsVersion="10.0">
<RuleHintPaths>
<Path>C:\App\PSI\Development\Source\JHA.ProfitStars.PSI\JHA.ProfitStars.PSI.FxCop\bin\Debug</Path>
</RuleHintPaths>
</RuleSet>
Also adding the rulesdll to Microsoft Visual Studio [Version]\Team Tools\Static Analysis Tools\FxCop\Ruleslocation would solve the issue of having to use Rulehintpaths.
As I can't detect anything wrong with your custom rules, see if you have selected the option to show all rules:
Also, using the following BaseRule might help:
protected BaseRule(string name)
: base(
// The name of the rule (must match exactly to an entry
// in the manifest XML)
name,
// The name of the manifest XML file, qualified with the
// namespace and missing the extension
typeof(BaseRule).Assembly.GetName().Name + ".Rules",
// The assembly to find the manifest XML in
typeof(BaseRule).Assembly)
{
}
Close your solution. Use the Source Control Explorer to locate your Rule Set File. Doubleclick onto your ruleset. The Rule Set Editor now should show all your custom rules. If this still doesn't work, try to use a relative path in the Path tag of the RuleHintPaths section.
Have a look at the LoadFromFile() method of the Microsoft.VisualStudio.CodeAnalysis.dll:
public static RuleSet LoadFromFile(string filePath, IEnumerable<RuleInfoProvider> ruleProviders)
{
RuleSet ruleSet = RuleSetXmlProcessor.ReadFromFile(filePath);
if (ruleProviders != null)
{
string relativePathBase = string.IsNullOrEmpty(filePath) ? (string) null : Path.GetDirectoryName(ruleSet.FilePath);
Dictionary<RuleInfoProvider, RuleInfoCollection> allRulesByProvider;
Dictionary<string, IRuleInfo> rules = RuleSet.GetRules((IEnumerable<string>) ruleSet.RuleHintPaths, ruleProviders, relativePathBase, out allRulesByProvider);
foreach (RuleReference ruleReference in (Collection<RuleReference>) ruleSet.Rules)
{
IRuleInfo ruleInfo;
if (rules.TryGetValue(ruleReference.FullId, out ruleInfo))
{
if (ruleInfo.AnalyzerId == ruleReference.AnalyzerId)
ruleReference.RuleInfo = ruleInfo;
else
CATrace.Info("RuleSet.LoadFromFile: Rule {0} was listed under analyzer id {1} in the rule set, but the corresponding IRuleInfo returned analyzer id {2}", (object) ruleReference.FullId, (object) ruleReference.AnalyzerId, (object) ruleInfo.AnalyzerId);
}
}
}
return ruleSet;
}
If the relativePathBase is calculated wrong, the rule DLLs will not be found.
I have made a script in C# that should load data from a XML file into a ListView.
This is the XML file I used to test :
<?xml version="1.0" encoding="utf-8"?>
<Items>
<wordExample languageOne="Пока" languageTwo="Doei" languageThree="Goodbye" />
<wordExample languageOne="1" languageTwo="2" languageThree="3" />
<wordExample languageOne="4" languageTwo="5" languageThree="6" />
<wordExample languageOne="7" languageTwo="8" languageThree="9" />
</Items>
Now I get an error when I try to load the XMl into the ListView and I really don't know what it could be, this is actually the first time I try to use XML in C#.
This is the code used to load the XML into the ListView :
public void ImportXMLToListView(ListView listview)
{
DialogResult dr = OPEN_FILE_DIA.ShowDialog();
if (dr == DialogResult.OK)
{
XDocument doc = XDocument.Load(OPEN_FILE_DIA.FileName);
int counter = 0;
foreach (var dm in doc.Descendants("Items"))
{
string tmpOne = dm.Attribute("languageOne").Value;
string tmpTwo = dm.Attribute("languageTwo").Value;
string tmpThree = dm.Attribute("languageThree").Value;
counter++;
ListViewItem lvi;
lvi = new ListViewItem(tmpOne);
lvi.SubItems.Add(tmpTwo);
lvi.SubItems.Add(tmpThree);
listview.Items.Add(lvi);
}
}
}
Am I doing something wrong??
This is the error I get : (Object reference not set to an instance of an object.)
Please tell me what I do wrong I really try to understand :S
language attributes belongs to your wordExample items. You need doc.Descendants("wordExample")
foreach (var dm in doc.Descendants("wordExample"))
{
string tmpOne = (string)dm.Attribute("languageOne");
string tmpTwo = (string)dm.Attribute("languageTwo");
string tmpThree = (string)dm.Attribute("languageThree");
...
}
And you can use explicit cast instead of directly accessing Value property to avoid NullReferenceException.