Paulo Morgado

.NET Development & Architecture

This Blog

Syndication

Search

Tags

News

Unit Test Today! Get Typemock Isolator!

Projects

Books

 

Visitors

Visitor Locations

Community

Email Notifications

Archives

Profile

Disclaimer

The opinions and viewpoints expressed in this site are mine and do not necessarily reflect those of Microsoft, my employer or any community that I belong to. Any code or opinions are offered as is. Products or services mentioned are purchased by me, made available to me by my employer or the manufacturer/vendor which doesn't influence my opinion in any way.

May 2007 - Posts

PDC 2007 Canceled

Seens like PDC 2007 has been postponed to a later date.

And this was the year I was all set up to go.

Well, I'm an optimist. This will make the TechEd Developer in Barcelona, Spain a better experience.

Posted Sun, May 27 2007 0:02 by Paulo Morgado | with no comments

Filed under: , , , ,

Paste From Visual Studio Plugin for Windows Live Writer

Reading Mike Gunderloy's Daily Grind 1146 I found out about this Paste From Visual Studio for Windows Live Writer.

I've been using Colin Colle's CopySourceAsHtml but I'll give this one a try.

Posted Sat, May 26 2007 23:26 by Paulo Morgado | with no comments

My Naming Conventions For Localized Concepts In C#

I'm Portuguese and most of the software I design and develop is about concepts in Portuguese. How should I name stuff?

If I'm talking about Conta or Cliente it's easy: Account and Customer. And what about concepts that aren't in English or for which a translation would be unrecognizable?

When I name stuff I try to make things easily recognizable for those who read it, and this brings us to a combination of both Portuguese and English.

When someone finds in the code or documentation ContaInválidaException (names are in Unicode, it's time to let go archaic prejudice - "conta invalida" means that the account is making something invalida and "conta inválida" means that the account is invalid) identifies immediately what it is. For a business person it's obvious that it's something about an invalid account and for a technology person it's obvious that it's some kind of exception.

Posted Fri, May 25 2007 0:23 by Paulo Morgado | 1 comment(s)

My C# Naming Conventions For Partial Class Files

Following up on a previous post, this time I'll give you my naming conventions for partial class files.

There are two main reasons for me to break a class definition into more than one file. The main one is when I have inner classes and the other is when the file is getting too big.

How should I name the files? The usual tendency is to use a “.” as separator. This looks nice until you came across something like this:

public class MyComponent

{

    private class Activation

    {

        // Class implementation.

    }

 

    private class Deployment

    {

        // Class implementation.

    }

 

    #region Event Handling

 

    // Event handling code.

 

    #endregion

}

If I would extract the inner classes and use the “.” as separator, I would end up with the following list of files:

  • MyComponent.Activation.cs
  • MyComponent.cs
  • MyComponent.Deployment.cs

And, what about the long event handling code? Should I do the same? If so, I will end up with the following list of files:

  • MyComponent.Activation.cs
  • MyComponent.cs
  • MyComponent.Deployment.cs
  • MyComponent.EventHandling.cs

This doesn’t look very nice, does it?

So, here is my proposal:

  • “-“ separator for code from the top class
  • “+” separator for inner classes

This way, I end up with the following list of files:

  • MyComponent.cs
  • MyComponent-EventHandling.cs
  • MyComponent+Activation.cs
  • MyComponent+Deployment.cs

And this looks a lot nicer.

Posted Thu, May 24 2007 0:29 by Paulo Morgado | 4 comment(s)

The Practices & Practices Team Is Requesting Feedback On What We Would Like Them To Build For The Web Client Software Factory

Glenn Blocks is requesting for feedback on what the p&p team should build for the next iteration of the Web Client Software Factory. If you have something in mind, let him know.

Posted Wed, May 23 2007 23:38 by Paulo Morgado | with no comments

Enterprise Library 3.1 Released

You can download here.

Before you get too excited, according to Tom Hollander, this is really just a maintenance release addressing a small number of issues discovered since the release of 3.0. Here is a summary of the main changes:

Policy Injection Application Block
  • The default Remoting Policy Injector can now be replaced with alternative interception mechanisms via configuration without modifying the application block code
  • Call Handler attributes are now honored correctly when placed on interface methods
  • Fixed an issue that could cause duplicate handlers where matching rules matched both a class and its interface
  • Classes implementing COM interfaces (including those deriving from System.Windows.Forms.Form) can now be intercepted
  • TraceLogEntry class is now serializable, allowing it to be used with the MSMQ Trace Listener
Validation Application Block
  • Fixed an issue that prevented the PropertyComparisonValidator from working with the Windows Forms integration adapter
  • The message template for the PropertyComparisonValidator can now be saved using the configuration tools.
Data Access Application Block
  • Connection strings for OLEDB and ODBC connections can now be edited using custom dialog boxes from the configuration tools

Posted Wed, May 23 2007 23:27 by Paulo Morgado | with no comments

NDepend 2.2 is now available to download

Check out the version release history to see what's new.

And Scott Dorman has a nice post about it, too.

Posted Wed, May 23 2007 14:22 by Paulo Morgado | with no comments

David S. Platt Has Posted An Event Visualizer for CAB

David S. Platt has posted an Event Visualizer for CAB. I'll have to check it out.

Posted Mon, May 21 2007 22:50 by Paulo Morgado | with no comments

Naming Conventions for C#

I'm a firm supporter of coding conventions (at least of my coding conventions).

Software factories [^] [^] [^] and other code generation tools have been taking care of writing the tedious (and, sometimes, ugly) code but, at some point, some code must be written and read by human developers. That's why (in my opinion) the way the code is written is as much important as the language it is written in.

There are several resources about coding conventions for the .NET framework:

I haven't read Brad and Krzysztof's book (yet), but I've read MSDN Library's guidelines and Juval's document and watched Krzysztof's presentation.

I have to disagree with Microsoft's position about naming conventions of private members. In an enterprise as big as Microsoft projects start and end, people move between teams and every time someone changes team he/she is faced with the possibility of having to learn and adapt to a new set of naming conventions for private members.

IDesign goes one step further on defining naming conventions for private members. I just don't like the convention they used. What's the point of prefixing private member fields (not variables as in their document) with m_? What does it mean? Member? If it's not a local method variable or a method parameter it's a member.

Some just prefix with _. Once again, why? What does that mean?

The only reason I can find for this prefixing practice is lost in the old days of colorless IDEs, printers and books. With colorful IDEs like Visual Studio 2005 you just need to qualify instance member fields with the this (Me for Visual Basic) keyword and static (Shared in Visual Basic) member fields with (lacking of a better solution) the class name.

Lets pretend for a moment that I'm one of the prefixes. How would I do it?

  • i_camelCase for private instance members.
  • s_camelCase for private static members.
  • c_camelCase for private constants.

Why stop there? Let's also prefix method variables:

  • v_camelCase for method variables.

Now I'm on a roll. Let's prefix method parameters:

  • i_camelCase for input parameters.
  • o_camelCase for output parameters.
  • r_camelCase for by reference parameters.

The next step would be to go Hungarian and add type information to the names, right? No. Let's stop here and get in the right track.

My Naming Conventions for C#

I Find that keeping naming conventions as simple as possible is the best way use and validate them.

  1. Pascal casing for any class/struct member (constants, fields, properties, methods, events) except for private fields.
  2. Camel casing for private fields and method/property parameters and variables.
  3. Prefix interface names with I (IAccountService).
  4. Prefix type parameter names with T (TKey, TValue).
  5. Suffix type with meaningful names for its purpose (AccountService, InvalidAccountException, MustVerifyAccountAttribute, FromAccountTextBox).
  6. Method names must reflect what they are supposed to do. Methods always do something, so they must start with a verb. (GetAccountInformation, UploadFile)
  7. Names must be descriptive. Abbreviations should not be used. Hungarian notation should not be used. Single name variables should not be used.
  8. Language keywords should be used instead of type names (string instead of System.String, int instead of System.Int32, etc.).
  9. Business relatad names should reflect business entities or actions, and in the business' language (GetContaFromDataBase, ContaInválidaException, ValidarContaAttribute).
  10. Underscores should not be used. Camel casing should be used to separate words.
  11. Acronyms should be treated as a single word. Just to be compliant with Microsoft, for acronyms with less than three letters, all letters should be upper case.

Posted Sun, May 20 2007 23:28 by Paulo Morgado | 27 comment(s)

TypeMocks™ 4.0.0 is now available

TypeMocks™ 4.0.0 is now available.

In my previous analysis mentioned two drwanbacks of this mocking framework:

  1. The lack of a mocking scope.
  2. The lack of the use of Generics in its APIs.

Let's start with the second one.

Generic Reflective API

TypeMocks™ was the same tool for both the .NET 1.1 and the .NET 2.0 runtimes and they were avoiding the need to have two tools. But we already need two runtimes and two IDEs, so two versions of TypeMocks™ isn't such an hassle. I'm glad they came to their senses about this.

Befere this new API, the usage of mocks was something like this:

MockObject mockObject = MockManager.MockObject(typeof(IIdentity));

mockObject.ExpectGetAlways("Name", "username");

IIdentity identity = (IIdentity)(mockObject.Object);

Now, it's more like this:

MockObject<IIdentity> mockObject = MockManager.MockObject<IIdentity>();

mockObject.ExpectGetAlways("Name", "username");

IIdentity identity = mockObject.Object;

You'll have to agree with me that the changes in lines 1 and 3 improve the reliability and readability of the test code.

Mocking Scope

The need for this one may not be obvious, so let's look at an example.

Imagine we are testing this class:

public class TestedClass

{

    string value;

 

    public TestedClass(bool create)

    {

        if (create)

        {

            this.value = new ClassUsedByTestedClass().Value;

        }

    }

 

    public string Value

    {

        get

        {

            return this.value;

        }

    }

}

As you can see, TestedClass uses ClassUsedByTestedClass:

public class ClassUsedByTestedClass

{

    public ClassUsedByTestedClass()

    {

        throw new NotImplementedException();

    }

 

    public string Value

    {

        get

        {

            throw new NotImplementedException();

        }

    }

}

Now, take these two tests:

[TestMethod()]

public void TestMethod1()

{

    const string mockedValue = "mocked value";

    const bool create = false;

 

    using (RecordExpectations recorder = RecorderManager.StartRecording())

    {

        ClassUsedByTestedClass c = new ClassUsedByTestedClass();

        string v = c.Value;

        recorder.Return(mockedValue);

    }

 

    TestedClass t = new TestedClass(create);

 

    Assert.AreEqual(mockedValue, t.Value);

}

 

[TestMethod()]

[ExpectedException(typeof(NotImplementedException))]

public void TestMethod2()

{

    const bool create = true;

 

    TestedClass t = new TestedClass(create);

}

These two tests will fail because the value of create in test one is wrong. To shield ourselves from this kind of mistakes, we can code the tests this way:

[TestMethod()]

public void TestMethod1()

{

    MockManager.ClearAll();

 

    const string mockedValue = "mocked value";

    const bool create = false;

 

    using (RecordExpectations recorder = RecorderManager.StartRecording())

    {

        ClassUsedByTestedClass c = new ClassUsedByTestedClass();

        string v = c.Value;

        recorder.Return(mockedValue);

    }

 

    TestedClass t = new TestedClass(create);

 

    Assert.AreEqual(mockedValue, t.Value);

 

    MockManager.Verify();

}

 

[TestMethod()]

[ExpectedException(typeof(NotImplementedException))]

public void TestMethod2()

{

    MockManager.ClearAll();

 

    const bool create = true;

 

    TestedClass t = new TestedClass(create);

 

    MockManager.Verify();

}

Now it's clear that the wrong test is the first one. But I like to scope things using the using statement, so, this is a better looking solution.

[TestMethod()]

public void TestMethod1()

{

    using (new MockScope())

    {

        const string mockedValue = "mocked value";

        const bool create = false;

 

        using (RecordExpectations recorder = RecorderManager.StartRecording())

        {

            ClassUsedByTestedClass c = new ClassUsedByTestedClass();

            string v = c.Value;

            recorder.Return(mockedValue);

        }

 

        TestedClass t = new TestedClass(create);

 

        Assert.AreEqual(mockedValue, t.Value);

    }

}

 

[TestMethod()]

[ExpectedException(typeof(NotImplementedException))]

public void TestMethod2()

{

    using (new MockScope())

    {

        const bool create = true;

 

        TestedClass t = new TestedClass(create);

    }

}

I would be very happy with this last solution. But both these two solutions have have too much mocking infrastruture coded in the test code and, because the people at TypeMocks™ aren't in the market of just making me happy, they came up with a better solution (available on Professional and Enterprise Editions only):

[TestMethod()]

[VerifyMocks]

public void TestMethod1()

{

    const string mockedValue = "mocked value";

    const bool create = false;

 

    using (RecordExpectations recorder = RecorderManager.StartRecording())

    {

        ClassUsedByTestedClass c = new ClassUsedByTestedClass();

        string v = c.Value;

        recorder.Return(mockedValue);

    }

 

    TestedClass t = new TestedClass(create);

 

    Assert.AreEqual(mockedValue, t.Value);

}

 

[TestMethod()]

[ExpectedException(typeof(NotImplementedException))]

[VerifyMocks]

public void TestMethod2()

{

    const bool create = true;

 

    TestedClass t = new TestedClass(create);

}

And do you know what they called this? Best Practices Patterns.

Generic Test Decorator

TypeMocks™ is more than just a mocking framework, and it now enables writing custom test decorators. These are test framework agnostic and it is simple to add more features to your tests. Now you can write your own version of VerifyMocksAttribute and ClearMocksAttribute (available on Enterprise Edidion only).

Mock Signed Internal Interfaces

It's now possible to mock internal interfaces in signed assemblies.

Enhancements to Natural TypeMocks™

It is now possible to create return values within the recording block, saving even more time and having an easier flow.

Before you had to do this:

DateTime d = new DateTime(2007, 5, 20);

using (RecordExpectations recorder = RecorderManager.StartRecording())

{

    TestedClass mc = new TestedClass(new DateTime());

    DateTime v = mc.Value;

    recorder.Return(d);

}

Now you can just do this:

using (RecordExpectations recorder = RecorderManager.StartRecording())

{

    TestedClass mc = new TestedClass(new DateTime());

    DateTime v = mc.Value;

    recorder.Return(new DateTime(2007, 5, 20));

}

There's also a ReturnDefaultImplementation method in the RecordExpectations class that returns a mock that has default behavior.

.. and several other enhancements and bug fixes.

Posted Sun, May 20 2007 20:34 by Paulo Morgado | with no comments

VSIPFactory - A Software Factory for Visual Studio Extensibility

The VSIPFactory is a software factory for Visual Studio extensibility.

Posted Sun, May 20 2007 17:00 by Paulo Morgado | with no comments

Smart Client Software Factory - May 2007 Release is Live

(From Blaine Wastell's post and Mariano Szklanny's post)

You can now download the SCSF - May 2007 release. The new release provides support for .NET 3.0. The release is propagating to the download servers and should be available when you read this. If not, be patient and try a little later.

The release provides:

  • Windows Presentation Foundation interoperability CAB extensions  and View with presenter recipe (don't miss this post from Miguel Saez for more details)
  • Offline application blocks and recipes; the application blocks support asynchronous calls to WCF web services.
  • Richer ClickOnce Deployment capabilities
  • Enhanced guidance packages which includes code generation Visual Basic .NET 2005 (don't miss this post from Juan Arguello for more details)
  • Improved installation with a new dependency checker
  • Compatibility with Enterprise Library 3.1.

Here are instructions to install the factory. The team has created a new Getting Starting topic on Codeplex. This topic includes instructions to create a Hello World Application with the factory.

Check it out and let them know how you like it.

And this means that the team is going to start it's work on the Web Client Software Factory.

Posted Sun, May 20 2007 12:35 by Paulo Morgado | with no comments

Developer Express won't be shipping 100 refactorings this year

Mark Miller has broken his promisse of shipping 100 Refactorings in 2007. And I'm glad he did. Read all about it.

Posted Sat, May 19 2007 1:03 by Paulo Morgado | with no comments

Refactor for ASP.NET version 2.2 is out

(This is not new, but ...)

Refactor! for ASP.NET version 2.2 is shipping. Built by Developer Express, this FREE code refactoring tool includes 29 time-saving refactorings and is available to all developers working in Visual Studio 2005 and Orcas Beta 1.

Read all about it in Mark's blog.

Posted Sat, May 19 2007 0:57 by Paulo Morgado | with no comments

UPDATE: Extension methods

Looks like I was way wrong in here and here.

I had thought that from the top of my head because I tried to use Array.IndexOf as an extension method and was surprised to see that it wasn't an extension method.

It presented a good opportunity to play around with extension methods, so I wrote a class to extend the Array class:

public static class ArrayUtils

{

    public static int IndexOf<T>(this T[] array, T value)

    {

        return System.Array.IndexOf(array, value);

    }

 

    public static int IndexOf<T>(this T[] array, T value, int startIndex)

    {

        return System.Array.IndexOf(array, value, startIndex);

    }

 

    public static int IndexOf<T>(this T[] array, T value, int startIndex, int count)

    {

        return System.Array.IndexOf(array, value, startIndex, count);

    }

}

It was so easy that I thought: "Why dind't they do it?".

While I was trying to write a proof of concept around making such a change in a class (changing normal static methods into extension methods). It was as simple as adding a this keyword:

public class MyClass

{

    private int myField;

 

    public int MyProperty

    {

        get { return myField; }

        set { myField = value; }

    }

 

    public static bool IsNullOrEmpty(this MyClass value)

    {

        if (value == null) return true;

        if (value.myField == 0) return true;

        return false;

    }

}

The output of the compiler just chilled my enthusiasm:

MyCsClass.cs(18,47): error CS1106: Extension methods must be defined in a non generic static class

What is this all about? How had I missed it in here and here?

Here's how I had missed it:

http://search.msdn.microsoft.com/search/Default.aspx?brand=msdn&query=%22non-nested%22+%22non-generic%22+%22static+class%22+%22extension+methods%22

http://search.live.com/results.aspx?q=%22non-nested%22+%22non-generic%22+%22static+class%22+%22extension+methods%22

I should have tried this:

http://www.google.com/custom?client=pub-3578125481836759&channel=1972798655&cof=S%3Ahttp%3A%2F%2Fsearchdotnet.com%2Fdefault.aspx%3BCX%3ADotNet%2520Developers%2520Search%2520Engine%3BL%3Ahttp%3A%2F%2Fwww.searchdotnet.com%2Fimages%2Fsearchnet.jpg%3BLH%3A36%3BLP%3A1%3B&q=%22non-nested%22+%22non-generic%22+%22static+class%22+%22extension+methods%22

THIS is the most recent (I think) specification of C# 3.0 and it states that:

Extension methods are declared by specifying the keyword this as a modifier on the first parameter of the methods. Extension methods can only be declared in non-generic, non-nested static classes.

Now it's all clear!

Posted Mon, May 14 2007 23:28 by Paulo Morgado | 3 comment(s)

How about a keyword for qualifying static members?

I like to always qualify all instance fields with the this keyword.

this.someInstanceField;

this.GetType();

I would like to do the same for static fields, but there's no keyword for that.

I've been thinking about this for a while and I think I found a solution: the static keyword.

typeof(); // no need for the static keyword

static.someStaticField;

Posted Sun, May 13 2007 23:30 by Paulo Morgado | 4 comment(s)

Extension methods missing from System.Array in the .NET Framework 3.5 (Beta 1)

UPDATE: Extension methods

Extension methods are a feature of the new C# language specification (also available in Visual Basic [^] [^]):

This new feature should be used in existing classes like the Array class by making the folowing methods extension methods:

public static System.Collections.ObjectModel.ReadOnlyCollection<T> AsReadOnly<T>(this T[] array);

public static int BinarySearch<T>(this T[] array, T value);

public static int BinarySearch(this Array array, object value);

public static int BinarySearch<T>(this T[] array, T value, System.IComparer<T> comparer);

public static int BinarySearch<T>(this T[] array, int index, int length, T value);

public static int BinarySearch<T>(this T[] array, int index, int length, T value, System.IComparer<T> comparer);

public static void ConstrainedCopy<T>(this T[] sourceArray, int sourceIndex, T[] destinationArray, int destinationIndex, int length);

public static TOutput[] ConvertAll<TInput, TOutput>(this TInput[] array, System.Converter<TInput, TOutput> converter);

public static void Copy<T>(this T[] sourceArray, T[] destinationArray, int length);

public static void Copy<T>(this T[] sourceArray, T[] destinationArray, long length);

public static void Copy<T>(this T[] sourceArray, int sourceIndex, T[] destinationArray, int destinationIndex, int length);

public static void Copy<T>(this T[] sourceArray, long sourceIndex, T[] destinationArray, long destinationIndex, long length);

public static bool Exists<T>(this T[] array, System.Predicate<T> match);

public static T Find<T>(this T[] array, System.Predicate<T> match);

public static T[] FindAll<T>(this T[] array, System.Predicate<T> match);

public static int FindIndex<T>(this T[] array, System.Predicate<T> match);

public static int FindIndex<T>(this T[] array, int startIndex, System.Predicate<T> match);

public static int FindIndex<T>(this T[] array, int startIndex, int count, System.Predicate<T> match);

public static T FindLast<T>(this T[] array, System.Predicate<T> match);

public static int FindLastIndex<T>(this T[] array, System.Predicate<T> match);

public static int FindLastIndex<T>(this T[] array, int startIndex, System.Predicate<T> match);

public static int FindLastIndex<T>(this T[] array, int startIndex, int count, System.Predicate<T> match);

public static void ForEach<T>(this T[] array, Action<T> action);

public static int IndexOf<T>(this T[] array, T value);

public static int IndexOf<T>(this T[] array, T value, int startIndex);

public static int IndexOf<T>(this T[] array, T value, int startIndex, int count);

public static int LastIndexOf<T>(this T[] array, T value);

public static int LastIndexOf<T>(this T[] array, T value, int startIndex);

public static int LastIndexOf<T>(this T[] array, T value, int startIndex, int count);

public static void Resize<T>(this ref T[] array, int newSize);

public static void Sort<T>(this T[] array);

public static void Sort<T>(this T[] array, System.IComparer<T> comparer);

public static void Sort<T>(this T[] array, System.Comparison<T> comparison);

public static void Sort<TKey, TValue>(this TKey[] keys, TValue[] items);

public static void Sort<T>(this T[] array, int index, int length);

public static void Sort<TKey, TValue>(this TKey[] keys, TValue[] items, System.IComparer<TKey> comparer);

public static void Sort<T>(this T[] array, int index, int length, System.IComparer<T> comparer);

public static void Sort<TKey, TValue>(this TKey[] keys, TValue[] items, int index, int length);

public static void Sort<TKey, TValue>(this TKey[] keys, TValue[] items, int index, int length, System.IComparer<TKey> comparer);

public static bool TrueForAll<T>(this T[] array, System.Predicate<T> match);

This would allow us to write code like this:

if (someArray.IndefOf(someValue))

{

    //...

}

If you would like to see this in the next release of the .NET framework, vote on this suggestion.

Posted Sun, May 13 2007 19:51 by Paulo Morgado | 1 comment(s)

Extension methods missing from System.String in the .NET Framework 3.5 (Beta 1)

UPDATE: Extension methods

Extension methods are a feature of the new C# language specification (also available in Visual Basic [^] [^]):

This new feature should be used in existing classes like the String class by making the folowing methods extension methods:

public static int Compare(this string strA, string strB);

public static int Compare(this string strA, string strB, bool ignoreCase);

public static int Compare(this string strA, string strB, System.StringComparison comparisonType);

public static int Compare(this string strA, string strB, bool ignoreCase, System.Globalization.CultureInfo culture);

public static int Compare(this string strA, int indexA, string strB, int indexB, int length);

public static int Compare(this string strA, int indexA, string strB, int indexB, int length, bool ignoreCase);

public static int Compare(this string strA, int indexA, string strB, int indexB, int length, System.StringComparison comparisonType);

public static int Compare(this string strA, int indexA, string strB, int indexB, int length, bool ignoreCase, System.Globalization.CultureInfo culture);

public static int CompareOrdinal(this string strA, string strB);

public static int CompareOrdinal(this string strA, int indexA, string strB, int indexB, int length);

public static string Concat(this string str0, string str1);

public static string Concat(this string str0, string str1, string str2);

public static string Concat(this string str0, string str1, string str2, string str3);

public static string Copy(this string str);

public static string Intern(this string str);

public static string IsInterned(this string str);

public static bool IsNullOrEmpty(this string value);

This would allow us to write code like this:

if (someString.IsNullOrEmpty())

{

    //...

}

If you would like to see this in the next release of the .NET framework, vote on this suggestion.

Posted Sun, May 13 2007 19:41 by Paulo Morgado | 1 comment(s)

The search engine every .NET developer was looking for

While watching this DotNetRocks show, I came across the SearchDotNet engine.

SearchDotNet comes in three flavors:

SearchDotNet has OpenSearch support which means that it can be added to the list of search engines in IE7 or Firefox 2.0 (or other OpenSearch client).

Daniel Appleman also keeps a list of other similar custom search engines.

Posted Mon, May 7 2007 23:25 by Paulo Morgado | 3 comment(s)

Optimizing reading for the CustomTextMessageEncoder

Continuing the improvement of the CustomTextMessageEncoder (see this and this), this time I'll use the XmlDictionaryWriter instead of the XmlTextWriter whenever the character encoding is utf-8, utf-16 or Unicode.

To achieve this, all that's needed is to look into the character set part of the content type and act accordingly.

public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)

{

    byte[] messageContents = new byte[buffer.Count];

    Array.Copy(buffer.Array, buffer.Offset, messageContents, 0, messageContents.Length);

    bufferManager.ReturnBuffer(buffer.Array);

 

    MemoryStream stream = new MemoryStream(messageContents);

    //return ReadMessage(stream, int.MaxValue);

    return ReadMessage(stream, int.MaxValue, contentType);

}

 

public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)

{

    string charset = null;

    if (!string.IsNullOrEmpty(contentType))

    {

        System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(contentType);

        charset = ct.CharSet;

    }

    if ((!string.IsNullOrEmpty(charset)) && (charset.Equals(ValidatingUTF8.WebName, StringComparison.InvariantCultureIgnoreCase) || charset.Equals(ValidatingUTF16.WebName, StringComparison.InvariantCultureIgnoreCase) || charset.Equals(ValidatingBEUTF16.WebName, StringComparison.InvariantCultureIgnoreCase)))

    {

        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, XmlDictionaryReaderQuotas.Max);

        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);

    }

    else

    {

        XmlReader reader = XmlReader.Create(stream);

        return Message.CreateMessage(reader, maxSizeOfHeaders, this.MessageVersion);

    }

}

Posted Mon, May 7 2007 21:45 by Paulo Morgado | 1 comment(s)

More Posts Next page »