Question

I have some code that uses SPWebConfigModification to add a couple of nodes to the system.webServer/modules section. What I want to do is add a <remove name="MyModule" /> and then an <add name="MyModule" type="[type full assembly path]">.

No matter what I seem to do though, the web.config always ends up with the <add ../> before the <remove ../>. This is obviously incorrect, as the module will be removed after it is added. What I want to do is remove it, then add it. Here is what the web.config ends up looking like:

<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
            <add name="MyModule" type="[type full assembly path]" />
            <remove name="MyModule" />
        </modules>
    </system.webServer>
</configuration>

Here is what I want it to look like:

<configuration>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
            <remove name="MyModule" />
            <add name="MyModule" type="[type full assembly path]" />
        </modules>
    </system.webServer>
</configuration>

..and here is the code, which gets executed during SPFeatureReceiver.FeatureInstalled:

SPSecurity.RunWithElevatedPrivileges(delegate
{
    SPWebService spWebService = SPWebService.ContentService;

    var moduleModification = new SPWebConfigModification
    {
        Path = "configuration/system.webServer/modules",
        Name = "remove[@name='MyModule']",
        Sequence = 0,
        Owner = "Sample",
        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
        Value = "<remove name='MyModule' />",
    };
    spWebService.WebConfigModifications.Add(moduleModification);
    spWebService.Update();
    spWebService.ApplyWebConfigModifications();

    moduleModification = new SPWebConfigModification
    {
        Path = "configuration/system.webServer/modules",
        Name = "add[@name='MyModule'][@type='[type full assembly path]']",
        Sequence = 1000,
        Owner = "Sample",
        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
        Value = "<add name='MyModule' type='type full assembly path' />",
    };
    spWebService.WebConfigModifications.Add(moduleModification);

    spWebService.Update();
    spWebService.ApplyWebConfigModifications();
});

... I know I am supposed to be able to make both of these changes before calling Update and ApplyWebConfigModifications, but just have this code in here this way because I can't figure out why it is putting the add above the remove. Why is it doing it this way? Is it trying to alphabetize the nodes? How can I specify the order?

Was it helpful?

Solution

Yes, the nodes are being alphabetically sorted and the Sequence property only applies when the Name property is exactly the same. To fix, use a little XPath trickery to get your nodes to sort in the correct order (first modules[1=1] then modules[2=2]):

SPSecurity.RunWithElevatedPrivileges(delegate
{
    SPWebService spWebService = SPWebService.ContentService;

    var moduleModification = new SPWebConfigModification
    {
        Path = "configuration/system.webServer",
        Name = "modules[1=1]/remove[@name='MyModule']",
        Sequence = 0,
        Owner = "Sample",
        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
        Value = "<remove name='MyModule' />",
    };
    spWebService.WebConfigModifications.Add(moduleModification);

    moduleModification = new SPWebConfigModification
    {
        Path = "configuration/system.webServer",
        Name = "modules[2=2]/add[@name='MyModule'][@type='[type full assembly path]']",
        Sequence = 1000,
        Owner = "Sample",
        Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode,
        Value = "<add name='MyModule' type='type full assembly path' />",
    };
    spWebService.WebConfigModifications.Add(moduleModification);

    spWebService.Update();
    spWebService.ApplyWebConfigModifications();
});

Also, you might want to double check what happens when you call ApplyWebConfigModifications to make sure your changes are propagated across the farm. Since you're calling it on an SPWebService I think it is OK but we always use the following:

webApp.Farm.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

Sources:

Licensed under: CC-BY-SA with attribution
Not affiliated with sharepoint.stackexchange
scroll top