How to read optional attributes in XML with default values

When we are reading data from XML data sources, it is very common that when a value is not given for an attribute or an element, we have to use a default value instead. Having to check for the existence of the node each and every time we are reading a value can be annoying and clutter the code. To address this issue I have made a few useful extension method that you can use copy and use in your code. These are written on top of XAttribute class, but you can write similar methods for other types and APIs pretty much the same way.

public static class XmlExtentions
{
    public static string ValueOrDefault(this XAttribute attr)
    {
        return ValueOrDefault(attr, string.Empty);
    }
    public static string ValueOrDefault(this XAttribute attr, string defaultValue)
    {
        return attr == null ? defaultValue : attr.Value;
    }

    public static T ValueOrDefault<T>(this XAttribute attr, T defaultValue) where T : struct
    {
        if (attr == null) { return defaultValue; }
        var value = attr.Value;
        var convertedValue = typeof(T).IsEnum ? Enum.Parse(typeof(T), value) : Convert.ChangeType(value, typeof(T));
        if (convertedValue == null) { return defaultValue; }
        return (T) convertedValue;
    }

    public static T ValueOrDefault<T>(this XAttribute attr, Func<T> defaultDelegate) where T : struct
    {
        if (attr == null) { return defaultDelegate(); }
        var convertedValue = Convert.ChangeType(attr.Value, typeof(T));
        if (convertedValue == null) { return defaultDelegate(); }
        return (T)convertedValue;
    }
}

Once you get it in place. It is pretty easy to use. Assume that we have the following XML document:

<Configuration>
    <Search Enabled="True" RankingAlghorithm="BS77" LowMark="1000" HighMark="2000">
        <Source Name="Orders" Type="WebService" />
        <Source Name="Products" Type="REST" />
    </Search>
<Configuration>

As is shown below, you can read any type of values exactly the same way.

// reading a bool
var isEnabled = sourceNode.Attribute("Enabled").ValueOrDefault(false);

// reading a string
var scopeName = sourceNode.Attribute("Name").ValueOrDefault("Default");

// reading a string and using empty string (string.Empty) as default value
var scopeName = sourceNode.Attribute("Name").ValueOrDefault();

// reading an enum
var sourceType = sourceNode.Attribute("Type").ValueOrDefault(SearchSources.Html);

// reading an integer
var lowMark = sourceNode.Attribute("LowMark").ValueOrDefault(100);

// Using a delegate to provide the default value
var highMark = sourceNode.Attribute("HighMark").ValueOrDefault(()=> App.GetUserSetting("Search.HighMark"));
Advertisements
How to read optional attributes in XML with default values

Disabling Security warning for Attach to process in Visual Studio 2010, 2013 and 2015

You probably have already suffered from the pain of having to click one more time when attaching visual studio’s debugger to a process. As developers we all have the obsession to be more productive and everything that comes in the way is a bummer. I should have shared this little secret before, but … I forgot.

You know this message box, right?

attach-security-warning1

Now when a colleague sent me a link to a blog post that explains how to change a registry key to disable the security warning in Visual Studio when attaching to processes, I decided to write a little “.reg” file to make it even easier for you. This warning is there to warn you when you are attaching the debugger to a process and that process is (that are running with different accounts than the one running Visual Studio)  The reg file works for Visual Studio 2010, 2013 and 2015 no matter which edition. You can view / download it from here:

Disabling Security warning for Attach to process in Visual Studio 2010, 2013 and 2015

Connecting WebParts programmatically in SharePoint

Let’s start by an example.

Example

In this blog post, I’m going to assume we have a webpart that displays a contact list and another one that displays a map with the possibility to pinpoint an address. To keep things simple I assume the address is merely a string.

public class Map : WebPart
{

}

public ContactList : WebPart
{
    [Personalizable]
    string SelectedAddress { get; set; }
}

To connect these webparts, we typically do the following four steps:

  • Write an interface to contain the information we need to transfer (i.e. Address)
  • Implement the interface in the provider webpart (i.e Map)
  • Write a callback method in the provider webpart to return the address.
  • Write another callback method in the consumer webpart to receive the address.
public interface IAddressConnection {
    string SelectedAddress { get; set; }
}

public class Map : WebPart
{
    [ConnectionConsumer(&quot;Pinpoint address&quot;, &quot;Address&quot;)]
    public void ConsumeAddress(ISelectedAddress address)
    {
        // Set the map extent and display a pinpoint.
    }
}

public ContactList : WebPart, IAddressConnection
{
    [Personalizable]
    public string SelectedAddress { get; set; }

    [ConnectionProvider(&quot;Selected address&quot;, &quot;Address&quot;)]
    public ISelectedAddress ProviderAddress()
    {
        return this;
    }
}

ConnectWebParts()

In order to connect two webparts, you need an instance of each webpart plus the WebPartManager (to be precise the SPLimitedWebPartManager) for the page they are hosted in and of course you need to know which of their connection points you are going to connect.

Let’s say you already have the WebPartManager and the two webparts at hand. In that case you can use the following method. Note that T is the interface these two webparts share.

public void ConnectWebParts(WebPartManager webPartManager, WebPart consumer, WebPart provider)
{
    var consumerConnection =
        webPartManager.GetConsumerConnectionPoints(consumer)
            .Cast&lt;ConsumerConnectionPoint&gt;()
            .FirstOrDefault(c =&gt; c.InterfaceType == typeof(T));
    var providerConnection =
        webPartManager.GetProviderConnectionPoints(provider)
            .Cast&lt;ProviderConnectionPoint&gt;()
            .FirstOrDefault(c =&gt; c.InterfaceType == typeof(T));
    webPartManager.ConnectWebParts(provider, providerConnection, consumer, consumerConnection);
}

The above method assumes that these webpart only have one connection point of type T, which makes sense most of the time, but in case your webpart have multiple connection points of the same interface.

By using ConnectWebParts method, we can easily connect the Map to the Contacts webpart.

ConnectWebParts&lt;IAddressConnection&gt;(webPartManager, map, contacts)

But, how to get the WebPartManager and instances of the webparts? you might ask. These webparts might be used in any page, but you definitely know on which page you are going to connect them. By having a reference to the page you can instantiate a WebPartManager and with that you can find you webparts too. If you are doing this in the code-behind of the page or a control (or webpart) in the page, you can do as following:

var webPartManager = WebPartManager.GetCurrentWebPartManager(this) // or this.Page if we are in a control.
var consumer =
    webPartManager.WebParts.Cast&lt;WebPart&gt;()
        .FirstOrDefault(w =&gt; w.GetType() == typeof(Map));
var provider =
    webPartManager.WebParts.Cast&lt;WebPart&gt;()
        .FirstOrDefault(w =&gt; w.GetType() == typeof(Contacts));
ConnectWebParts&lt;IAddressConnection&gt;(webPartManager, consumer, provider)

What if the code is not running in the page? Then you need to get an instance of the page. Let’s use SPLimitedWebPartManager this time.

using (var site = new SPSite(&quot;http://mydomain/mysite&quot;))
{
    var file = site.RootWeb.GetFile(&quot;myfolder/mypage.aspx&quot;);
    var webPartManager = file.GetLimitedWebPartManager(PersonalizationScope.Shared);
    var consumer =
        webPartManager.WebParts.Cast&lt;WebPart&gt;()
            .FirstOrDefault(w =&gt; w.GetType() == typeof(Map));
    var provider =
        webPartManager.WebParts.Cast&lt;WebPart&gt;()
            .FirstOrDefault(w =&gt; w.GetType() == typeof(Contacts));
    ConnectWebParts&lt;IAddressConnection&gt;(webPartManager, consumer, provider)
}

Please note that you might need to checkout the page, publish and approve it if versioning or approval workflow has been enabled on the library that contains the page.

I hope you find it useful. By the way, don’t forget the null checks!

Connecting WebParts programmatically in SharePoint