Visual Studio 2010 introduces new and cool feature – architecture diagrams that visualize dependencies between assemblies, namespaces and classes. In this posting I will show you how these diagrams look like and provide some explanations about how to read them.
I tested architecture diagrams (or should I say dependency diagrams?) with one of my small projects. Okay, I tried to visualize dependencies found in source code of KiGG too but it was too big for current implementation of dependency visualizer. But for smaller projects it works pretty well.
You can find these diagrams from Architecture menu of Visual Studio 2010.
Assembly dependencies
As a first thing I generated dependency diagram for assemblies. There is one main dll and it is related to violet block labeled as Generics. Blue block is my assemby and generics block shows all the generics I am using. Externals block is for external assemblies and on the following screenshot it is expanded so you can see other assemblies on what my own assembly one depends.
Visual Studio 2010: Assembly dependencies diagram.
Click on image to view it at original size.
Namespace dependencies
Namespace dependencies diagram illustrates dependecies between namespaces. Also here you can see Generics and Externals boxes. Purpose of them is same as before. On the following screenshot you can see class dependencies in my project. Bookmarks2LiveWriter box is expanded and it contains classes in this namespace. Class ExceptionBox is also expanded and you can see how method dependencies are visualized.
Visual Studio 2010: Namespace dependencies diagram.
Click on image to view it at original size.
Class dependencies
Class dependencies diagram illustrates dependencies between classes. As on previous diagrams you can see also on this diagram the lines with different thickness between classes. Thickness of line gives you some idea about how dependent one class is of another. Thicker line means heavier dependency. Direction on line shows what class is using what other class.
Visual Studio 2010: class dependencies diagram.
Click on image to view it at original size.
Custom dependencies
You can also generate custom dependency diagrams that illustrate things ust like you want. The result is something like you can see on screenshots above. Only new thing is dialog that lets you specify what you can see on diagram.
You can see this dialog on right and if it is too small for you then please click on it to see it at original size.
Right are in this dialog is reserved for example diagram. If you change the state of check boxes you can see on example how generated diagram looks like. After clicking Ok custom architecture diagram will be generated.
Matrix View
It is possible to view dependencies also as matrix. You can see dependencies matrix on following screenshot. You can see that I have disabled some options in legend – it is because otherwise matrix will be very large.
Visual Studio 2010: Matrix view of dependencies.
Click on image to view it at original size.
Conclusion
Dependency diagrams are very useful tools when you analyze dependencies between different components in your system. Less dependencies mean usually less problems because changing one part of system causes less changes to other parts of system. I think these diagrams are good addition to code analysis reports because sometimes one picture can tell more than 1000 words.
Currently dependency diagrams are generated pretty slowly. But I hope it will me much faster when first stable version of Visual Studio 2010 hits the streets. Currently you can save diagrams as XPS files and it also possible to copy diagram or legend to clipboard as image. It is pretty easy to take those diagrams and make them part of your project documents.
uberVU is service that monitors how your blog entries (or other web resources) are performing in different social networks. You can integrate uberVU reaction count badge to your blog and monitor popularity of your blog entries right in your blog. In this posting I will show you how to add uberVU badge to your blog without any server-side coding.
You can find uberVU patch from uberVU tools page. There is also JavaScript given that you can use on your blog or home page. If you plan to insert this badge manually then you don’t need any additional work. But I am lazy guy and I want to put it up once so it works for all pages in my blog.
The example JavaScript is as follows (of course, uberVU may change it as they wish):
<script type="text/javascript">
var ubervu_url = "http://your-url";
var ubervu_title = "Your Page Title";
var ubervu_style = "regular";
</script>
<script type="text/javascript" src="http://badge.ubervu.com/badge.1.0.js"></script>
But here are some problems:
- you must hardcode URL of the page,
- you must hardcode page title.
With couple of lines of code you can make it work on all of your pages. If uberVU badge code looks still like this then you can use the following code that works for every page.
<script>
var url = document.location.href;
if(url.indexOf('#') > -1)
url = url.substr(0, url.indexOf('#'));
var ubervu_url = url;
var ubervu_title = document.title;
var ubervu_style = "regular";
</script>
<script type="text/javascript" src="http://badge.ubervu.com/badge.1.0.js"></script>
Basically I just find current page URL and title with JavaScript and assign them to appropriate uberVU variables. Easy! :)
Visual Studio 2010 introduces modeling projects that bring UML diagrams to Visual Studio. Currently it is not possible to generate classes from diagrams automatically but I don’t think it is a problem – good UML diagrams visualize different aspects of system short and clearly and they usually don’t document everything you can find in system. In this posting I will show you how to use modeling projects in Visual Studio 2010.
Creating modeling projects
Modeling projects are created as all other projects. Select New Project from menu and select Modeling Projects from templates pane. There is only one modeling project template called (very originally) Modeling Project. Select it and click Ok.
Modeling project is practically empty when it is created. On the left side of screen you should see UML Model Explorer (you can open it from View => Other Windows menu). To add new objects to UML model just right click on the title with mouse and select object type.
UML Model Explorer
You can see UML Model Explorer on image at right. I took this screenshot after adding some objects to my modeling project so you can see how this window looks like when there is some content.
You can add new objects to you model simply by right clicking on model name and selecting object type you want to add. You can define object attributes and assign values to its properties right in the UML Model Explorer.
As a next thing let’s see some example diagrams I created. There are some features I miss (like saving diagrams as image files) but diagramming works pretty fine for program in beta status. Here are my example diagrams.
Adding new diagram
New diagrams are added to model just like any other file in other projects. Just select Add new item and select item type. You can click on image below to see it at original size.
You can see in the item types list all diagrams you can add to modeling project. I am not very sure if this list is final or not because some diagram types are missing. But let’s hope the best as always.
Adding items to diagrams
After adding new diagram or opening existing ones you can add objects to diagram. You can find objects specific to diagram from toolbox. Screenshots below show you toolboxes for activity, class and user case diagrams.
Class diagram
UML class diagram shows classes in system (or subsystem) and relations between classes. Modeling projects show also attributes and methods of classes. I created simple class diagram that visualizes Party generalization and shows how this generalization can easily connect addresses to Person and Company classes.
If you have larger model that doesn’t fit to screen well you can hide members area of classes and save some more room for classes that are not visible otherwise.
Use case diagram
UML use case diagrams illustrate use cases in system (or subsystem) and actors who are related to use cases. Also relations between use cases are shown and commented if needed. My example shows simple registration process where user is identified by its digital passport and then approved by adminitrator when registration data is saved.

Activity diagram
As final example here is my activity diagram. It is simple one and it only shows you how activity diagrams look like – don’t look for any deep thoughts from this example.
There are also some good news about modeling projects. If you read Code stubbing with Visual Studio 2010 UML modeling thread from Visual Studio 2010 Beta 2 forums you can find out that modeling projects are built as easily extensible parts of projects and Microsoft is working also on code generation features. So, stay tuned – something big is happening!
Here are some download links to Visual Studio 2010 Beta 2 and related technologies.
Visual Studio
Team Foundation Server
Visual Studio SDK-s
Learn
Cropping images in ASP.NET is easy task to do if you use right tools. In this posting I will introduce how to crop images using Jcrop and System.Drawing namespace classes. What we are building is simple and user-friendly image cropping interface that also demonstrates some simple features of Jcrop. Believe me, your users will love it!
Jcrop is jQuery based library that brings crop margins selection to client side. Before starting you need two (free) JavaScript libraries:
After downloading them create new ASP.NET Web Application project and unpack those libraries to js directory. Also copy file js/Jcrop/css/Jcrop.gif to root folder of your project and add image you want to crop to same folder.
Expected result
As a first thing we will show image to user and some informative labels under image. And, of course, there is button for cropping.
You can see those values changing under image when you change the size or location of cropping are box.
When user clicks crop button then image will be cropped and shown to user. In our current case the result will be something like shown on following screenshot.
You can crop image again and again and again until you get the result you like.
Code
This is my ASP.NET form. I have to warn you that my JavaScript is written just to make it work and it needs some more cosmetics if you plan to use this code in real development. So, no hard feelings, okay?
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Crop.aspx.cs" Inherits="BlogExamples.Crop" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
<link rel="Stylesheet" type="text/css" href="js/Jcrop/css/jquery.Jcrop.css" />
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/Jcrop/js/jquery.Jcrop.min.js"></script>
<script type="text/javascript">
var editorID = '<%= _imageEditor.ClientID %>';
jQuery(function() {
jQuery('#' + editorID).Jcrop({
onChange: showCoords,
onSelect: showCoords
});
});
function showCoords(c) {
var tdX = document.getElementById('tdX');
var tdY = document.getElementById('tdY');
var tdWidth = document.getElementById('tdWidth');
var tdHeight = document.getElementById('tdHeight');
tdX.innerHTML = c.x;
tdY.innerHTML = c.y;
tdWidth.innerHTML = c.w;
tdHeight.innerHTML = c.h;
var xField = document.getElementById('<%= _xField.ClientID %>');
var yField = document.getElementById('<%= _yField.ClientID %>');
var widthField = document.getElementById('<%= _widthField.ClientID %>');
var heightField = document.getElementById('<%= _heightField.ClientID %>');
xField.value = c.x;
yField.value = c.y;
widthField.value = c.w;
heightField.value = c.h;
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Image runat="server" ID="_imageEditor" ImageUrl="MY_FILE.JPG" />
</div>
<table border="0" cellpadding="2" cellspacing="0">
<tr>
<td>x:</td>
<td id="tdX">-</td>
<td>y:</td>
<td id="tdY">-</td>
<td>width:</td>
<td id="tdWidth">-</td>
<td>height:</td>
<td id="tdHeight">-</td>
<td><asp:Button runat="server" ID="_cropCommand" onclick="_cropCommand_Click" Text="Crop" /></td>
</tr>
</table>
<input type="hidden" runat="server" id="_xField" />
<input type="hidden" runat="server" id="_yField" />
<input type="hidden" runat="server" id="_widthField" />
<input type="hidden" runat="server" id="_heightField" />
</form>
</body>
</html>
And here is code-behind file of my form. If you plan to use this code in real development then you must validate values of crop margins before using them with drawing methods. Also you need error handling and you have to make sure that all objects will be disposed correctly.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Web.UI;
namespace BlogExamples
{
public partial class Crop : Page
{
protected void _cropCommand_Click(object sender,
EventArgs e)
{
var x = int.Parse(_xField.Value);
var y = int.Parse(_yField.Value);
var width = int.Parse(_widthField.Value);
var height = int.Parse(_heightField.Value);
using(var photo =
Image.FromFile(Server.MapPath("MY_IMAGE.JPG")))
using (var result =
new Bitmap(width, height, photo.PixelFormat))
{
result.SetResolution(
photo.HorizontalResolution,
photo.VerticalResolution);
using (var g = Graphics.FromImage(result))
{
g.InterpolationMode =
InterpolationMode.HighQualityBicubic;
g.DrawImage(photo,
new Rectangle(0, 0, width, height),
new Rectangle(x, y, width, height),
GraphicsUnit.Pixel);
photo.Dispose();
result.Save(Server.MapPath("MY_IMAGE.JPG"));
}
}
}
}
}
Well, that’s it. If you have any troubles running this code then please drop me a comment here and I will try to help you.
Next version of .Net Framework brings some new features also to VB.NET. One of those new features is support for automatic properties. C# automatic properties are here from .Net Framework 3.5 and now are them also in VB.NET. In this posting I will show to VB.NET users how to use automatic properties and explain why to use them.
Take a look at the following class created in Visual Studio 2010.
Public Class Person
Public Property FirstName As String = "John"
Public Property LastName As String
Private strSSN As String
Public Property SSN()
Get
SSN() = strSSN
End Get
Set(ByVal value)
strSSN = value
End Set
End Property
End Class
There are three properties: FirstName, LastName and SSN. FirstName and LastName are automatic properties. They are automatic because after compiling they look almost like SSN property – the variable that holds property value is created automatically. If you are interested in internals of automatic properties then you may read my blog posting Is Automatic Property Same as Property?
Property initialization
As you can see from class above you can assign initial values to automatic properties. You don’t have to write constructor to class just to initialize properties that have simple value types. Of course, compilator generates default constructor if you don’t write one but what you win is shorter code.
Less unit test
SSN is classic property and it is up to programmer to handle value of the property correctly. As people are error prone then it is easy to make mistakes in classic properties. Specially if internal variables have similiar names. To avoid those problems you write unit tests for properties – just to make sure your properties are handling their internal variables correctly.
With automatic properties you don’t need those tests. Testing automatic property is pointless – if it is broken then all the .Net Framework is broken and I am pretty sure you are not able to run Visual Studio in this case.
If you have 100 classes and each of them has 10 simple properties you can remove 1000 unit tests if you start using automatic properties.
Less code
The main point of automatic properties is to avoid writing unnecessary code. When I converted one of my code examples from C# to VB.NET I was amazed how long code I got. Of course… I decided not to publish this code here (imho every good programmer should know some Java-like language and I really ignore whining like why-this-code-is-not-vbnet).
If you look at code example above and make some easy calculations then you should find out that you win 7 lines on code per one property if you start using automatic properties. For class with 10 simple properties where property only returns or sets the value of internal variable you can delete 70 lines of code from your class. If you have 100 classes with 10 simple properties you can delete 7000 lines of unnecessary code. Cool, isn’t it?
Conclusion
Automatic properties are really powerful feature that helps you keep code shorter and easier to read and maintain. Also you don’t have to worry about typos in internal variable names that properties use. As a blogger I am happy because now I can publish VB.NET examples besides C# ones and I can be sure that these examples are not horribly long due to unnecessary code anymore.
When I started building in-house demo application I thought about how to solve temporary data layer so I don’t have to use real database and object mappings for it. Playing with new object model and new components I move way faster if I don’t have any additional ballast that I can avoid. So I wrote simple cache based repository mechanism I can use to imitate real repositories that I will write in the future.
NB! Don’t develop this idea too much further because you can use my method only to some certain point. Don’t forget that you have also maintain relations between objects and keep them consistent. Use my method until your object model is small and simple.
If you look for something perfect you don’t find it here. It is just my pretty raw solution that I still test and I am not very sure if I don’t replace it with something better soon.
Structure of my application
Basically my application follows structure show here (example data, just took it from air):
- AppName.Core (all business classes and interfaces are here)
- Contacts
- Projects
- Project.cs
- ProjectTask.cs
- …
- Repositories
- IPersonRepository
- ICompanyRepository
- …
- BusinessEntity.cs
- AppName.Data.CacheBasedStorage (this is the topic of this posting)
- Repositories
- BaseRepository.cs
- PersonRepository.cs
- CompanyRepository.cs
- …
- AppName.Data.NHibernate (not there really, but comes if users like my app)
- AppName.Infrastructure (IoC, validation and other “low level” stuff)
- Resolver.cs
- Validator.cs
- …
- AppName.Web (web version of my application)
I think this structure tells almost everything about architecture. Okay, some notes too. AppName.Core has only interfaces for repositories because it doesn’t deal with objects persisting and doesn’t provide any Data Access Layer logic. It is all done in external repository implementations. I use Unity as IoC container and Resolver class in infrastructure library is mediator between client applications and repository implementations. I can always move from Unity to some other IoC container and client applications doesn’t need to be built again.
Why cache based storage?
I considered different ways about how to implement my toy-repositories and cache seemed to me as pretty good option:
- it is accessible to all users of my application,
- it is easy to use,
- it needs no additional coding for saving and loading data,
- it’s not a problem when data expires – I need data for building and demonstration purposes only.
Of course, it is also possible to use some more elegant solutions but … I am just too lazy to run for idealism and beautiful things. When I get something that works right now for me – I am happy. In this point I don’t know if users like my app or not and I don’t want to make any moves I can avoid.
Implementation of repositories
Cache based data storage implementation is in AppName.Data.CacheBasedStorage library. In short we have abstract class BaseRepository that does all the dirty work for us. The real repositories extend it and they also follow repository interfaces from core library. Basically they wrap calls to base library with correct types.
Let’s start with BaseRepository. The implementation shown here is awful in multi-user context, but for one-man testing and developing it is okay.
public abstract class BaseRepository
{
private Cache _cache;
protected BaseRepository()
{
// Here we add some sample data to cache
}
private Cache Cache
{
get
{
if (_cache != null)
return _cache;
_cache = HttpContext.Current.Cache;
return _cache;
}
}
protected T Get<T>(int id)
{
var list = GetList<T>();
if (list == null)
return default(T);
if (list.ContainsKey(id))
return list[id];
return default(T);
}
protected void Save<T>(T instance) where T : BusinessEntity
{
var list = GetList<T>();
var id = instance.Id;
if (id == 0)
{
if (list.Count > 0)
id = (from l in list
orderby l.Key descending
select l.Key).First();
id++;
instance.Id = id;
if (list.ContainsKey(id))
list[id] = instance;
else
list.Add(id, instance);
}
else
list[id] = instance;
}
protected void Delete<T>(T instance) where T : BusinessEntity
{
var list = GetList<T>();
if (list.ContainsKey(instance.Id))
list.Remove(instance.Id);
}
protected IDictionary<int, T> GetList<T>() where T : BusinessEntity
{
var type = typeof(T).ToString();
if (Cache[type] != null)
return (IDictionary<int, T>)Cache[type];
var list = new Dictionary<int, T>();
Cache[type] = list;
return list;
}
}
Now you may have question: what about data querying? My answer is simple: let’s take LINQ and use it. We don’t have tons of data, we don’t have millions of users – we have only our development machine and one or two users.
And here is one example repository. It is very simple and as stated above it just wraps calls to base repository with correct types. Of course, if I need some more logic in repositories then I can add it to appropriate methods. Later, if users like my applications, I can take this logic from my toy-repositories and put it in real repositories.
public class CompanyRepository : BaseRepository, ICompanyRepository
{
public Company GetCompanyById(int id)
{
return Get<Company>(id);
}
public CompanyName GetCompanyNameById(int id)
{
return Get<CompanyName>(id);
}
public IList<Company> ListCompanies()
{
return GetList<Company>().ToList();
}
private void Save(Company company)
{
Save<Company>(company);
}
public void SaveCompanyName(CompanyName name)
{
Save<CompanyName>(name);
}
public void Delete(Company company)
{
Delete<Company>(company);
}
public void DeleteCompanyName(CompanyName name)
{
Delete<CompanyName>(name);
}
}
Well, this is my current experiment with repositories that should save me some time and be flexible enough to get working prototypes done. I also like the idea that I can keep my object model evolving with my prototype so I create additional value when building prototypes – when I have to start real coding I can use classes I wrote during prototyping and hopefully it saves me some time.
In my last posting I introduced new ReadLines() method and new overloads for WriteAllLines() method of File class. But there are more new stuff in System.IO namespace. In .Net Framework 4.0 Directory and DirectoryInfo class are able to enumerate files, directories and file system entries. In this posting I will show you these new features.
Let’s see now how to enumerate file system objects using new static methods of Directory class. There is one thing you should know. If you have to handle files and directories in same context then you should use EnumerateFileSystemEntries() method that enumerates both files and directories. The following example shows you how to enumerate different file system objects.
static void Main(string[] args)
{
var path = Path.GetPathRoot(Environment.CurrentDirectory);
var files = Directory.EnumerateFiles(path);
var directories = Directory.EnumerateDirectories(path);
var entries = Directory.EnumerateFileSystemEntries(path);
Console.WriteLine("Files:");
foreach (var file in files)
Console.WriteLine(file);
Console.WriteLine("\r\nDirectories:");
foreach (var directory in directories)
Console.WriteLine(directory);
Console.WriteLine("\r\nEntries:");
foreach (var entry in entries)
Console.WriteLine(entry);
Console.ReadLine();
}
You should get output like this (the path is root path of drive where application is located).
Files:
C:\autoexec.bat
C:\config.sys
C:\pagefile.sys
Directories:
C:\$Recycle.Bin
C:\Documents and Settings
C:\Install
C:\PerfLogs
C:\Program Files
C:\ProgramData
C:\Recovery
C:\System Volume Information
C:\Users
C:\Windows
Entries:
C:\$Recycle.Bin
C:\autoexec.bat
C:\config.sys
C:\Documents and Settings
C:\Install
C:\pagefile.sys
C:\PerfLogs
C:\Program Files
C:\ProgramData
C:\Recovery
C:\System Volume Information
C:\Users
C:\Windows
These enumerating methods work better than ones that return arrays because requests to file system are made only when concrete object is asked from enumerator. I think these methods may be very good load balancers in applications that make heavy use of file system.
.Net Framework 4.0 adds also some new and cool features to file system objects. File class has now ReadLines() methods that returns IEnumerable<string>. WriteAllLines() methods has two overload methods that accept IEnumerable<string> instead of strings array that was also supported in previous versions of .Net Framework. This posting introduces ReadLines() and WriteAllLines() methods and gives you some ideas how to use these methods in your applications.
Querying file contents
My first example shows how to use ReadLines() to query file contents using LINQ. I have text file called lorem-ipsum.txt with some paragraphs with famous lorem ipsum text. You can generate your own text on www.lipsum.com. I use LINQ query to get all lines from this file that contain word ipsum.
static void Main(string[] args)
{
var lines = File.ReadLines("lorem-ipsum.txt");
var ipsumQuery = from l in lines
where l.ToLower().Contains("ipsum")
select l;
foreach (var ipsumLine in ipsumQuery)
{
Console.WriteLine(ipsumLine);
}
Console.ReadLine();
}
Even if you don’t use LINQ you can still consider using ReadLines() method – it doesn’t load all the contents from file to memory like ReadAllLines() does. When you are working with large files then ReadLines() is extremely useful method for you.
Writing query contents to file
My second example shows you how to write contents of IEnumerable<string> to file. ReadAllLines() method of File class has now two new overloads that accept IEnumerable<string>. To get example done with less effort we will use previous example and instead of printing lines to screen we will output them to separate file.
static void Main(string[] args)
{
var lines = File.ReadLines("lorem-ipsum.txt");
var ipsumQuery = from l in lines
where l.ToLower().Contains("ipsum")
select l;
File.WriteAllLines("only-ipsum.txt", ipsumQuery);
Console.ReadLine();
}
Although this example is not something markable or revolutionary it illustrates you how to query one file and output results to another file. Of course, you can use instead of file query everything else that implements IEnumerable<string> interface.
There is also AppendAllLines() method that appends lines to file instead of overwriting the file like WriteAllLines() does.
In my opinion these features are very good ones and you can use these methods in all of your applications where you need to read and query or query something and write results to files.
.Net Framework 4.0 Beta 2 has new IsNullOrWhiteSpace() method for strings generalizes IsNullOrEmpty() method to incluse also other white space besides empty string. In this posting I will show you simple example that illustrates how to use IsNullOrWhiteSpace() method.
Term “white space” includes all characters that are not visible on screen. By example, space, line break, tab and empty string are white space characters. The following example shows how to use IsNullOrWhiteSpace() method.
static void Main(string[] args)
{
string helloString = "Hello, world!";
string nullString = null;
string emptyString = string.Empty;
string whiteSpaceString = "\t\r\n ";
Console.WriteLine("Is null or whitespace?");
Console.WriteLine("-----------------------");
Console.WriteLine("helloString: " + string.IsNullOrWhiteSpace(helloString));
Console.WriteLine("nullString: " + string.IsNullOrWhiteSpace(nullString));
Console.WriteLine("emptyString: " + string.IsNullOrWhiteSpace(emptyString));
Console.WriteLine("whiteSpaceString: " + string.IsNullOrWhiteSpace(whiteSpaceString));
Console.ReadLine();
}
When you run this example you get the following output.
Is null or whitespace?
-----------------------
helloString: False
nullString: True
emptyString: True
whiteSpaceString: True
IsNullOrWhiteSpace() is useful in scenarios where string to be checked may contain some white space characters instead of null or empty string. You can use this method to check values that user inserts to form fields, by example.
Also you can use this method with fixed-length character fields in database. These fields left-pad their values with spaces to field length and if database provider doesn’t trim values of these fields automatically you can use IsNullOrWhiteSpace() methods to check if field has value or not.
IsNullOrWhiteSpace() for older .Net Framework versions
If you like IsNullOrWhiteSpace() method but you cannot move to .Net Framework 4.0 you can use helper class with IsNullOrWhiteSpace() method. Yes, you have to use some helper class because you cannot add static extension methods to existing classes without recompiling them.
public static class StringHelper
{
public static bool IsNullOrWhiteSpace(string s)
{
if (s == null)
return true;
return (s.Trim() == string.Empty);
}
}
Well, that’s it. If you have some interesting uses for IsNullOrWhiteSpace() method then feel free to drop a comment here.
More Posts
Next page »