Sharepoint web.config changes using SPWebConfigModification - c#

I've written a sharepoint application that needs to change web.config
I have a feature that is supposed to make all these configurations. The code for that feature is like this:
SPSite site = properties.Feature.Parent as SPSite;
List<SPWebConfigModification> modifications = new List<SPWebConfigModification>();
modifications.AddRange(CustomErrorsModeConfig.Modifications);
webConfigModificationHelper.AddWebConfigModifications(site.WebApplication, modifications);
CustomErrorsModeConfig.Modifications property contains this code:
public static SPWebConfigModification[] Modifications = {
new SPWebConfigModification()
{
Owner = WebConfigModificationOwner,
Name = "mode",
Type = SPWebConfigModification.SPWebConfigModificationType.EnsureAttribute,
Path = "system.web/customErrors",
Sequence = 0,
Value = "Off"
}
};
Then finally the webConfigModificationHelper.AddWebConfigModifications method:
foreach (SPWebConfigModification modification in modifications)
{
webApp.WebConfigModifications.Add(modification);
}
webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();
webApp.Update();
The problem is that I keep getting this error:
Name cannot begin with the ''' character, hexadecimal value 0x27. Line 1, position 1453
Could this be a problem with the web.config before I try to apply my changes ?
Could the SPWebConfigModification property be incorrectly defined ?
Is there some glitch in my code that leads to this error ?
Might there be some property I am missing (e.g. web.AllowUnsafeUpdates) ?
Some sharepoint site configuration ?
I've been trying to solve this issue for some time now with no luck :( Any ideas ?

I can recommend using stsadmwebconfig for making changes to web.config files. I've implemented this in many features and it has always been a pain, especially while developing. Using this tool makes it a lot easier.

Ive seen this before when the file format is not correctly set between the file and the declaration.
Open the web.config file into a advanced text editor (Notepad++ or Visual Studio) and manually force the file type to match what is specified. Usually its going to be UTF-8.
For more info:
http://www.dumpsterdoggy.com/tutorials/?xmlexception-name-cannot-begin-with

Try taking the List template and for loop out and set the property using straightforward syntax. Here's a post for setting the property in your example, see if you can get this to work and then progress to building up a more generic solution with a List and iteration over the items in the list.
http://www.sharepointkings.com/2008/05/how-to-modify-webconfig-file-in.html

Related

Find out the source control state of a ProjectItem from a Visual Studio extension

I'm currently developing a Visual Studio extension. For a new feature I need to find out whether a given ProjectItem (file) was modified (has "Pending Changes" since the last commit). For this I would like to query the source control provider.
I already tried searching all the properties of the ProjectItem but there is nothing hidden in there.
I also tried getting a service associated with source control from the Package.cs. I tried getting IVsSccManager2, IVsSccManager3 and IVsSccGlyphs. All return null (the test project is under source control). edit: I try to get these services by calling GetService(typeof(IVsSccManager2)) inside my Package.cs. The source control plugin of my debugging session correctly shows the changed files at the time this is called.
I can't seem to find anything online about this topic. How can I find out the modified state? Is it even possible?
After letting this topic sit for some time I recently came back to it and found the solution thanks to the help of my collegue. The problem was that I had no experience in bitwise comparison so I didn't know how to handle the response properly. Luckily my collegue gave me the right tip.
To interpret the result of status (thanks to #simon-mourier for the help on this code):
uint[] sccStatus = new uint[] { 0 };
if (VSConstants.S_OK == manager.GetSccGlyph(1, new[] { filePath }, new[] { VsStateIcon.STATEICON_NOSTATEICON }, sccStatus))
{
__SccStatus status = (__SccStatus)sccStatus[0];
}
One has to do bitwise comparison with the state of __SccStatus you are looking for, for example:
if ((sccStatus[0] & (uint)__SccStatus.SCC_STATUS_RESERVED_2) != 0)
return true;
The comparison returns true in case the state is set. If you need help on what specific state combinations can mean, just comment here and I can help on that.

How can I check if some IIS modules are present

I am working on an installer and am looking to programatically check in IIS (7 and above) to see if certain modules are present.
This will have to work on Windows server 2008 R2 and above.
I am looking for AppWarmupModule and DynamicCompressionModule.
Any info or suggestions would be much appreciated.
Load the contents of the file:
C:\Windows\System32\inetsrv\config\applicationHost.config
You can put it into a XML document and use xPath to find
<configuration><system.webServer><globalModules><add name="DynamicCompressionModule"
or string-parse or Regex the content otherwise to find out whether the strings you are looking at are present.
Solving similar problem for IIS10, but also for installation to remote servers. Direct reading xml file is not solution for me.
In my case, I need to find if AspNetCoreModuleV2 is installed or not, but this should works for every module.
Based on Microsoft docs I used approach below. It returns list of globalModules in applicationHost.config for selected server. (with using Microsoft.Web.Administration)
internal static ConfigurationElementCollection GetModules(string remoteServerName = null)
{
ServerManager mgr;
mgr = string.IsNullOrEmpty(remoteServerName) ? new ServerManager() : ServerManager.OpenRemote(remoteServerName);
Configuration config = mgr.GetApplicationHostConfiguration();
ConfigurationSection globalModulesSection = config.GetSection("system.webServer/globalModules");
ConfigurationElementCollection globalModulesCollection = globalModulesSection.GetCollection();
return globalModulesCollection;
}
And then simple enumerate:
ConfigurationElementCollection modules = GetModules();
foreach (var item in modules)
{
System.Diagnostics.Debug.WriteLine(item.Attributes["name"].Value);
// do whatever you want
}

ActiveDirectory error 0x8000500c when traversing properties

I got the following snippet (SomeName/SomeDomain contains real values in my code)
var entry = new DirectoryEntry("LDAP://CN=SomeName,OU=All Groups,dc=SomeDomain,dc=com");
foreach (object property in entry.Properties)
{
Console.WriteLine(property);
}
It prints OK for the first 21 properties, but then fail with:
COMException {"Unknown error (0x8000500c)"}
at System.DirectoryServices.PropertyValueCollection.PopulateList()
at System.DirectoryServices.PropertyValueCollection..ctor(DirectoryEntry entry, String propertyName)
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Entry()
at System.DirectoryServices.PropertyCollection.PropertyEnumerator.get_Current()
at ActiveDirectory.Tests.IntegrationTests.ObjectFactoryTests.TestMethod1() in MyTests.cs:line 22
Why? How can I prevent it?
Update
It's a custom attribute that fails.
I've tried to use entry.RefreshCache() and entry.RefreshCache(new[]{"theAttributeName"}) before enumerating the properties (which didn't help).
Update2
entry.InvokeGet("theAttributeName") works (and without RefreshCache).
Can someone explain why?
Update3
It works if I supply the FQDN to the item: LDAP://srv00014.ssab.com/CN=SomeName,xxxx
Bounty
I'm looking for an answer which addresses the following:
Why entry.Properties["customAttributeName"] fails with the mentioned exception
Why entry.InvokeGet("customAttributeName") works
The cause of the exception
How to get both working
If one wants to access a custom attribute from a machine that is not
part of the domain where the custom attribute resides (the credentials
of the logged in user don't matter) one needs to pass the fully
qualified name of the object is trying to access otherwise the schema
cache on the client machine is not properly refreshed, nevermind all
the schema.refresh() calls you make
Found here. This sounds like your problem, given the updates made to the question.
Using the Err.exe tool here
http://www.microsoft.com/download/en/details.aspx?id=985
It spits out:
for hex 0x8000500c / decimal -2147463156 :
E_ADS_CANT_CONVERT_DATATYPE adserr.h
The directory datatype cannot be converted to/from a native
DS datatype
1 matches found for "0x8000500c"
Googled "The directory datatype cannot be converted to/from a native" and found this KB:
http://support.microsoft.com/kb/907462
I have the same failure. I´m read and saw a lot of questions about the error 0x8000500c by listing attribute from a DirectoryEntry.
I could see, with the Process Monitor (Sysinternals), that my process has read a schema file. This schema file is saved under
C:\Users\xxxx\AppData\Local\Microsoft\Windows\SchCache\xyz.sch.
Remove this file and the program works fine :)
I just encountered the issue and mine was with a web application.
I had this bit of code which pulls the user out of windows authentication in IIS and pulls their info from AD.
using (var context = new PrincipalContext(ContextType.Domain))
{
var name = UserPrincipal.Current.DisplayName;
var principal = UserPrincipal.FindByIdentity(context, this.user.Identity.Name);
if (principal != null)
{
this.fullName = principal.GivenName + " " + principal.Surname;
}
else
{
this.fullName = string.Empty;
}
}
This worked fine in my tests, but when I published the website it would come up with this error on FindByIdentity call.
I fixed the issue by using correct user for the app-pool of the website. As soon as I fixed that, this started working.
I had the same problem with a custom attribute of a weird data type. I had a utility program that would extract the value, but some more structured code in a service that would not.
The utility was working directly with a SearchResult object, while the service was using a DirectoryEntry.
It distilled out to this.
SearchResult result;
result.Properties[customProp]; // might work for you
result.Properties[customProp][0]; // works for me. see below
using (DirectoryEntry entry = result.GetDirectoryEntry())
{
entry.Properties[customProp]; // fails
entry.InvokeGet(customProp); // fails as well for the weird data
}
My gut feel is that the SearchResult is a little less of an enforcer and returns back whatever it has.
When this is converted to a DirectoryEntry, this code munges the weird data type so that even InvokeGet fails.
My actual extraction code with the extra [0] looks like:
byte[] bytes = (byte[])((result.Properties[customProp][0]));
String customValue = System.Text.Encoding.UTF8.GetString(bytes);
I picked up the second line from another posting on the site.

How to correctly iterate application settings in C# using reflection

I am trying to iterate through application properties in C# using reflection (.NET 3.5 using VS 2010). The code "works" in that it successfully gets properties. However, it always gets the property values that were defined at design time and does not see the current values in myapp.exe.config. Properties that I access directly by name do reflect what is in the .config file. Here is the reflection-based code which only sees design-time properties:
List<StringDictionary> dictList = new List<StringDictionary>();
StringCollection bogus = new StringCollection();
foreach (PropertyInfo info in Properties.Settings.Default.GetType().GetProperties())
{
if (!("logLevel".Equals(info.Name) || "eventURL".Equals(info.Name)))
{
if (bogus.GetType().IsAssignableFrom(info.PropertyType))
{
StringCollection rawConfig = (StringCollection)info.GetValue(Properties.Settings.Default, null);
// do something
}
}
}
This code does pick up the current values in myapp.exe.config.
String logLevelStr = Properties.Settings.Default.logLevel
What am I doing wrong in my reflection code that causes me to pull only the properties defined at design time and not what is currently in myapp.exe.config?
To get the current value you need to use something like this which looks at Default.PropertyValues instead of Default.Properties
foreach (SettingsPropertyValue property in Properties.Settings.Default.PropertyValues)
{
Debug.WriteLine(string.Format("Property {0}'s value is {1}",property.Name,property.PropertyValue));
}
// note: the above may not work in some multi-form app, even if the applicaton prefix is prepended in front of Properties esp for visual studio 2010 compiled app with .net frame work 4
I think that there is a fundamental misunderstanding here. Settings can be one of two types- Application settings and User settings.
Application settings are intended to be written only at design time. As Henk points out it is possible to edit them after deployment if you are admin, but that isn't really the intent. Also, it should be noted that while Application settings are stored in the .config file, they are only read once and then cached in memory. That's why you don't see the new values when you edit the file.
User settings can be overwritten at run time by application code and saved, but they are saved at a user scope, so a different user running the same application can have different values. The intention there was things like user preferences. There is a drop down in the settings designer grid to switch between Application and User scope for each Setting.
Either way, you shouldn't be accessing them via reflection.
There must be some kind of misunderstanding here.
If you want to read the configurations from myapp.exe.config you should use ConfigurationManager. This class allows you to access AppSettings and ConnectionString directly through static properties or read custom sections by the GetSection method.
Beside, application configurations are meant to be design-time only. You shouldn't alter myapp.exe.config at runtime. Never. This file must be the same for each execution of your application.
Beside, what is Properties.Settings.Default.logLevel ???
Consider:
foreach (SettingsProperty sp in Settings.Default.Properties)
{
Console.WriteLine(sp.Name + "=" + Settings.Default.Properties.Default[sp.Name].ToString());
}

c#: Create new settings at run time

c# windows forms: How do you create new settings at run time so that they are permanently saved as Settings.Default.-- values?
Just in case that still matters to anyone:
You can dynamically add settings through Settings.Default.Properties.Add(...) and have these also persisted in the local storage after saving (I had those entries reflected in the roaming file).
Nevertheless it seems that the dynamically added settings keep missing in the Settings.Default.Properties collecion after loading again.
I could work around this problem by adding the dynamic property before first accessing it.
Example (notice that I "create" my dynamic setting from a base setting):
// create new setting from a base setting:
var property = new SettingsProperty(Settings.Default.Properties["<baseSetting>"]);
property.Name = "<dynamicSettingName>";
Settings.Default.Properties.Add(property);
// will have the stored value:
var dynamicSetting = Settings.Default["<dynamicSettingName>"];
I don't know if this is supported by Microsoft as the documentation is very rare on this topic.
Problem is also described here http://www.vbdotnetforums.com/vb-net-general-discussion/29805-my-settings-run-time-added-properties-dont-save.html#post88152 with some solution offered here http://msdn.microsoft.com/en-us/library/saa62613(v=VS.100).aspx (see Community Content - headline "How to Create / Save / Load Dynamic (at Runtime) Settings"). But this is VB.NET.
In addition to John's solution for saving, the proper method for loading is add the property, and then do a Reload() on your settings.
Your dynamic setting will be there!
For a full example, valid for using in library code, as you can pass the settings in ..
ApplicationSettingsBase settings = passed_in;
SettingsProvider sp = settings.Providers["LocalFileSettingsProvider"];
SettingsProperty p = new SettingsProperty("your_prop_name");
your_class conf = null;
p.PropertyType = typeof( your_class );
p.Attributes.Add(typeof(UserScopedSettingAttribute),new UserScopedSettingAttribute());
p.Provider = sp;
p.SerializeAs = SettingsSerializeAs.Xml;
SettingsPropertyValue v = new SettingsPropertyValue( p );
settings.Properties.Add( p );
settings.Reload();
conf = (your_class)settings["your_prop_name"];
if( conf == null )
{
settings["your_prop_name"] = conf = new your_class();
settings.Save();
}
Since the Settings class is generated at build time (or, actually, whenever you update the settings file from within the designer), you can't use this mechanism for dynamic scenarios. You can, however, add some collection or dictionary to the application settings and modify that dynamically.
You can't add settings directly (at least not without editing the config XML at runtime), but you can fake it.
In my case, I had a group of identical custom controls on the form, and I wanted to store the runtime state of each control. I needed to store the state of each control, since each one had different data it.
I created a new StringCollection setting named ControlData and placed my own data in there. I then load the data from that list and use it to initialize my controls.
The list looks like this:
Box1Text=A
Box1List=abc;def;foo;bar;
Box2Text=hello
Box2List=server1;server2;
In my startup code, I read through the key/value pairs like this:
foreach (string item in Properties.Settings.Default.ControlData) {
string[] parts=item.split('=');
parts[0] will have the key and parts[1] will have the value. You can now do stuff based on this data.
During the shutdown phase, I do the inverse to write the data back to the list. (Iterate through all the controls in the form and add their settings to ControlData.
How would you access the new settings that you have created? The point of the Visual Studio settings designer is that you can write code that uses these settings with compile-time checking of your code. If you want to dynamically create new settings for your app to use, you will also need to dynamically load them. For dynamic settings, you may want to look at the System.Configuration assembly, notably ConfigurationSection. You can create a custom configuration section with that, which you could use for dynamic setting addition/removal. You might use a ConfigurationCollection for that dynamic addition/removal.
INI files eh? Google turned up this INI library for .NET.
What you could do is create a new registry key.
Name the new key "Your program settings".
RegistryKey ProgSettings = Registry.CurrentUser.OpenSubKey("Software", true);
ProgSettings.CreateSubKey("Your Program settings");
ProgSettings.Close();
Now you can add String Identifiers and values.
RegistryKey ProgSettings = Registry.CurrentUser.OpenSubKey("Software\\Your Program settings", true);
ProgSettings.SetValue("Setting Name", value); // store settings
string settings = ProgSettings.GetValue("Setting Name", false); // retreave settings
ProgSettings.DeleteValue("Setting Name", false);
Besure to close the registry key when you are done to avoid conflicts with other parts of your program that may write to the registry.
Many comercial software applications use these methods.
stackoverflow has many examples about writing and reading to the registry.
This is much easyer then modifying the appconfig.xml file that is used when you create settings.
It took me a long time using the top two answers here plus this link (Create new settings on runtime and read after restart) to get it to finally work.
First of all, set your expectations. The answer here will create a new user setting and you can get its value the next time you launch your app. However, the setting you created this way will not appear in the Settings designer. In fact, when you relaunch the app and try to access the setting in your code, it will not find it. However, the setting you have created through code is saved in the user.config file (say jDoe.config) somewhere in your file system. For you to access this value, you have to add the setting again.
Here is a working example I have:
private void FormPersistence_Load(object sender, EventArgs e)
{
StartPosition = FormStartPosition.Manual;
// Set window location
var exists = Settings.Default.Properties.OfType<SettingsProperty>().Any(p => p.Name == Name + "Location");
if (exists)
{
this.Location = (Point)Settings.Default[Name + "Location"];
}
else
{
var property = new SettingsProperty(Settings.Default.Properties["baseLocation"]);
property.Name = Name + "Location";
Settings.Default.Properties.Add(property);
Settings.Default.Reload();
this.Location = (Point)Settings.Default[Name + "Location"];
}
}
Note:
My new setting's name will be resolved at run time. Name is really this.Name, which is the form's name. This is a base form that other forms can inherit from, so all the child forms will be able to remember their locations.
baseLocation is a setting I have manually created in Settings designer. The new setting I have is the same type. This way I don't have to worry about things like provider, type, etc. in code.
I see how what I wanted was the wrong idea. I'm porting a c++ app over to c# and it has a lot of ini file settings and I was looking for a shortcut to add them in. I'm lazy.

Categories