Feeds:
Posts
Comments

Archive for the ‘Code’ Category

If you use KnockoutJS and want your input-fields to automatically grow and shrink with the input, use this custom handler.

Usage

<input 
  type="text" 
  data-bind="autosize: {
    maxWidth: 500, 
    minWidth: 100, 
    comfortZone: 15
}"/>

Code

Original code from javascript - Is there a jQuery autogrow plugin for text fields?

ko.bindingHandlers.autosize = {
   init: function(element, valueAccessor, allBindingsAccessor, viewModel) {
        var o = $.extend({
           maxWidth: 1000,
           minWidth: 0,
           comfortZone: 70
       }, valueAccessor());
        var minWidth = o.minWidth || $(element).width(),
           val = '',
           input = $(element),
           testSubject = $('<tester/>').css({
               position: 'absolute',
               top: -9999,
               left: -9999,
               width: 'auto',
               fontSize: input.css('fontSize'),
               fontFamily: input.css('fontFamily'),
               fontWeight: input.css('fontWeight'),
               letterSpacing: input.css('letterSpacing'),
               whiteSpace: 'nowrap'
           }),
           check = function() {
                if (val === (val = input.val())) {
                   return;
               }
                // Enter new content into testSubject
               var escaped = val.replace(/&/g, '&amp;').replace(/\s/g, ' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
               testSubject.html(escaped);
                // Calculate new width + whether to change
               var testerWidth = testSubject.width(),
                   newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
                   currentWidth = input.width(),
                   isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                       || (newWidth > minWidth && newWidth < o.maxWidth);
                // Animate width
               if (isValidWidthChange) {
                   input.width(newWidth);
               }
            };
        testSubject.insertAfter(element);
        ko.utils.registerEventHandler(element, 'keyup keydown blur update', check);
    }
    };

Read Full Post »

With this simple snippet, all clicks on page-internal anchors, external links (http…) and mailto-links are tracked as events in Google Analytics:

$(function(){
    $("a[href*='http']").each(function() {
                    $(this).click(function (ev) {
                        var pageView = '/outgoing/' + $(this).attr('href');
                        _gat._getTrackerByName()._trackEvent('Outbound Links', pageView);
                        var _href = $(this).attr('href');
                        setTimeout(function() {
                            location.href = _href;
                        }, 100);
                        ev.preventDefault();
                        return false;
                    });
        });
      $("a[href*='mailto']").each(function() {
                    $(this).click(function (ev) {
                        var pageView = '/mailto/' + $(this).attr('href').substring(7);
                        _gat._getTrackerByName()._trackEvent('Mailto', pageView);
                    });
        });
      $("a[href*='#']").each(function() {
                    $(this).click(function (ev) {
                        var pageView = '/anchor/' + $(this).attr('href').substring(1);
                        _gat._getTrackerByName()._trackEvent('Anchors', pageView);
                    });
        });
});

Read Full Post »

I’ll make it short: it’s a mess. You can’t use plexus container 1.5-tooling (with java annotations), if you have to load your components in a plexus 1.0.x-container – which is the case, if your components are utilized in a Maven 2.2.x Mojo. This is simply because plexus container 1.5.x uses “default” as a default role-hint, while NULL is the default in plexus 1.0.x.

But you can use the old tooling, plexus-maven-plugin. But by default it fails if it sees any annotation in your source code, because it uses a version of qdox that doesn’t know annotations yet.

Also, when generating the component descriptor it doesn’t merge with the manually defined one in src/resources (the new one does).

And since, by default, the merge-descriptors goal runs before descriptor (generate) goal, you have to do some back flips to get that running too.

Well here is a configuration that works. At least in my project. Today.

<plugin>
  <groupId>org.codehaus.plexus</groupId>
  <artifactId>plexus-maven-plugin</artifactId>
  <version>1.3.8</version>
  <dependencies>
    <dependency>
      <groupId>com.thoughtworks.qdox</groupId>
      <artifactId>qdox</artifactId>
      <version>1.12</version>
    </dependency>
  </dependencies>
  <executions>
    <execution>
      <phase>process-classes</phase>
      <goals>
        <goal>descriptor</goal>
        <goal>merge-descriptors</goal>
      </goals>
      <configuration>
        <!-- descriptor config -->
        <outputDirectory>${project.build.directory}</outputDirectory>
        <fileName>plexus/auto-components.xml</fileName>

        <!-- merge config -->
        <descriptors>
          <descriptor>${project.build.directory}/plexus/auto-components.xml</descriptor>
          <descriptor>${basedir}/src/main/resources/META-INF/plexus/components.xml</descriptor>
        </descriptors>
      </configuration>
    </execution>
  </executions>
</plugin>

Note: If you only want to use automatic descriptors, remove all <configuration>…</configuration> contents. The defaults will work then.

You can define that in build/pluginManagement/plugins in your parent pom. Then in your project pom, you just put these four lines in build/plugins:

<plugin>
  <groupId>org.codehaus.plexus</groupId>
  <artifactId>plexus-maven-plugin</artifactId>
</plugin>

Read Full Post »

As I’m doing some work for the NPanday Visual Studio Addin, I bugs me even more that my Visual Studio 2010 currently needs about 40 seconds to start.

Actually I do not wonder at all, as I installed every single extension I ever found interesting. But, should I now disable them all, or rather find out which one takes the most time?

I did the latter.

After reading Did you know… There’s a way to have Visual Studio log its activity for troubleshooting? – #366 via (visual studio – VS2010 loads slowly. Can I profile extensions’ respective startup time? – Stack Overflow)

There it says, that if you start VS using devenv /Log, it will log it’s acitivity to  %AppData%\Roaming\Microsoft\VisualStudio\10.0\ActivityLog.xml (for VS 2010). And it even comes with an XML that provides some output:

image

New XSL with Profiling Capabilities

So I tweaked the XSL to be a little bit more “profiling-friendly”. It will now:

  • Tell me how long it took load each package
  • Give me a visual indicator each 1 second (configurable)
  • Mark each “End package load” line red, that exceeds a certain configurable threshold (default 500 ms).
  • Mark each normal line read, if it exceeds the configured threshold.

image

image

Hotspots

image

Download and use with GIT

  1. Open Commandwindow in %AppData%\Roaming\Microsoft\VisualStudio\10.0
  2. Run git clone https://github.com/lcorneliussen/ActivityLogProfiler
  3. Start Visual Studio with ‘/Log’ switch
  4. Run deploy.cmd (will overwrite default ActivityLog.xsl in parent folder; Visual Studio will replace it after restart!)
  5. Open ActivityLog.xml in Internet Explorer

You can also download it manually (from here) and replace %AppData%\Roaming\Microsoft\VisualStudio\10.0\ActivityLog.xsl manually after each Visual Studio Run.

But with GIT you can easily get updates; and it makes it easier to submit patches, which I’ll be happy to apply.

Attention: Now you only have to repeat 3) and 4) to produce new logs, as Visual Studio will recreate both ActivityLog.xml and ActivityLog.xsl each time it is started with ‘/Log’.

Read Full Post »

Sometimes, from a concrete type, you need to find out if it implements a specific generic type or interface, and even more interesting, which concrete type arguments it uses in it’s implementation.

Since this information can be “hidden” somewhere in the type hierarchy, I created some helper extension methods that help finding this information and released them as a Minimod. What is a Minimod?

It can answer these simple questions:

Is List<Int32> an IEnumerable<T>? yes
If it is, what are the type parameters? Int32

Is Dictionary<Int32,String> an IDictionary<TKey,TValue>? yes
If it is, what are the type parameters? Int32,String

This is the test/example code generating them:

[Test]
public void PrintExamples()
{
    printExample(typeof(List<int>), typeof(IEnumerable<>));
    printExample(typeof(Dictionary<int, string>), typeof(IDictionary<,>));
}

private static void printExample(Type type, Type genTypeDef)
{
    bool isOfGenericType = type.IsOfGenericType(genTypeDef);

    Console.WriteLine("Is {0} an {1}? {2}",
                      type.GetPrettyName(),
                      genTypeDef.GetPrettyName(),
                      isOfGenericType ? "yes." : "no.");

    if (isOfGenericType)
    {
        Console.WriteLine("If it is, what are the type parameters? "
                          + type.GetGenericArgumentsFor(genTypeDef)
                                .Select(_ => _.GetPrettyName())
                                .JoinStringsWith(", "));
    }
}

Summary

The Minimod adds to System.Type the following extension methods:

  • bool IsOfGenericType(this Type type, Type genericTypeDefinition)
  • Type[] GetGenericTypesFor(this Type type, Type genericTypeDefinition)
  • Type GetGenericTypeFor(this Type type, Type genericTypeDefinition)
  • Type[] GetGenericArgumentsFor(this Type type, Type genericTypeDefinition)

Get it!

It is published to Nuget as a Minimod: NuGet gallery

Other minimods are also available there: Packages - NuGet gallery

Original source code is found at: minimod/minimods - GitHub

Read Full Post »

I once wrote this, but then never posted it. Thought it could be a good article – but never polished it enough. So here it is; untouched from somewhere in 2009, hence outdated?; still too good content to keep it for myself…

Code is available here: lcorneliussen/Discovering-Entity-Framework

LINQ to Entities is great for demos

Ever since the ADO.NET Entity Framework 1.0 released as a part of .NET 3.5 SP1 in August 2008 it has gotten a lot of bad press. This article is not about bad press. It’s about real world project experiences, where we hit walls almost everywhere we tried to go with Entity Framework. Our Scenario is maybe not the most common one, but exactly that’s where EF proves that it’s not mature enough for production.

You know those scenarios where you have to implement real world requirements? Those, where telling your customer that you can’t implement a certain requirement because your framework doesn’t support it, would barely help?

Well, than we are on the same page!

Scenario

Let me introduce you to our scenario. We have a set of plug-ins organized by categories. Every plug-in manages it’s own tables, but the framework requires some certain tables and columns per category. The data is managed by some legacy DAOs.

Let’s say, just to prevent being fired, we have a plugin-category “People” and two plug-ins named “Singles” and “Spouses” managing some people together their cars.Bild 5

And another category

Now, as in every real world product, we need to easily query this data without having to care about all the different tables. So we decided to dynamically create views on top of each of the different plug-in-tables that fake a consistent relational model per Plug-in-Category:

Bild 7

This, as we thought, could be easily mapped to a object structure letting a O/R-mapper do all the complex joining and sub querying over the admittedly much larger production model.

Choosing a Product

My customer, as many customers are, was afraid of using something that does not come from Redmond. Since this scenario is so simple I decided to give both EF and LINQ2SQL a chance.

Relationships (Many-to-Many) were easier to model in EF, so I went for it.

After overcoming some initial problems, as were

  • While generating the Entities for my views it turned out db-views support in EF is quite poor. It just sets all non-null-fields as compound entity keys. After changing it to something more natural, you can’t update your model from the database anymore. This makes changes quite expensive in this case.
  • Mapping one-to-many in the designer feels quite unnatural.

… finally I got it working. And it demos very well!! But that is basically what it does. It demos well. Not more.

Bild 8

Almost every real task I had to solve using EF was a nightmare! First of all let me tell about the difference between LINQ, LINQ-to-SQL, EF, LINQ to Entities and EF Object Query. If you know all about these, just skip it.

LINQ

Linq is a set of interfaces and extension methods, a C#/VB.NET language feature plus a runtime that enables Language-INtegrated Querying against any structured data source. See here for a list of LINQ implementations, and here. If you want to know more on the background, read this.

## LINQ example (on IQueryable and IEnumerable) ##

LINQ to SQL

LINQ to SQL is way to often just refereed to as LINQ. That is simply wrong. LINQ is neither the same as LINQ to SQL, nor is it any O/R-mapper implementation.

Instead, as Microsoft released the language feature along C# 3.0 and the .NET Framework 3.5, they also delivered some implementation for LINQ as LINQ to XML, LINQ to Objects, LINQ-to-SQL and LINQ to DataSet.

EF (Entity Framework)

In addition, Microsoft released another O/R-mapper called ADO.NET Entity Framework. Using EF, the user can choose between querying via the embedded LINQ support called LINQ to Entities, or using Object Queries.

LINQ to Entities

LINQ to Entities simply is a implementation for querying Entity Framework using LINQ-syntax. This gives you nice features as type safety, selecting subsets using anonymous types, and so on.

var query = from p in model.AllPeople
            where p.Age > 30
            select p.Name;

foreach (var name in query)
{
    Console.WriteLine(name);
}

/* Results
*  Michael Jendryschik (A)
*  Michael Kloss (B)
*/

EF Object Query

Object Queries are similar to SQL, but operates on the conceptual object model. It does not offer type safety, but enables much more sophisticated queries.

Within Object Queries you can either use the Query Builder Methods:

var query = model.AllPeople
    .Where("it.Age > @age", new ObjectParameter("age", 30))
    .SelectValue<string>("it.Name");

… or go for manual queries using Entity SQL:

var query = model.CreateQuery<string>(
    "SELECT VALUE p.Name FROM AllPeople AS p WHERE p.Age > @age", 
    new ObjectParameter("age", 30));

All these queries result into the same query:

SELECT 
[Extent1].[Name] AS [Name]
FROM (SELECT 
      [AllPeople].[Id] AS [Id], 
      [AllPeople].[Name] AS [Name], 
      [AllPeople].[Age] AS [Age]
      FROM [dbo].[AllPeople] AS [AllPeople]) AS [Extent1]
WHERE [Extent1].[Age] > 30

So what to choose? Choice necessary?

Problems with LINQ to Entities and/or Object Query

The problem is, that LINQ and ObjectQuery operate on the same objects, but still have a separate architecture. Sometimes it is mixable, sometimes it’s not.

ef-arch

ObjectQuery<T> and IQueryable<T>

Since ObjectQuery<T> implements IQueryable (which is default for LINQ queries) you get all Query Builder Methods plus all default LINQ extension methods for IQueryable.

As soon as you execute one of the many nice Extension Methods you’re locked into LINQ to Entities which won’t let you specify any ObjectQuery-specific Expressions on top anymore. But you can start with Object Query and then use LINQ-queries against ObjectQueries.

Queryable and ObjectQuery 

So what? Then let’s just use LINQ to Entities, right?

Lets sum up the good news about LINQ to Entities first:

  • Nice syntax for those who are used to it
  • Type safety !!!
  • Very easy to join relationships (OK in Object Query)
  • Simple sub-queries using Any(…)
  • Very easy to use with anonymous types 
    (which are not really good supported in ObjectQuery)

Well, the problem is, that you can get very, very far with LINQ to Entities and then suddenly you’ll hit the wall. It has some pretty major limitations that in my opinion make it unsuitable for production use:

Back to some queries

Let me demonstrate those problems using some simple queries.

“List all people with their cars, ordered by the model name”

from p in model.AllPeople
from c in p.Cars
orderby c.Model
select new { p.Name, c.Model };

/* Results
* { Name = Michael Kloss (B), Model = Mercedes E350 CDI Coupé }
* { Name = Lars Corneliussen (B), Model = Skoda Oktavia }
* { Name = Lars Corneliussen (B), Model = VW Fox }
* { Name = Michael Jendryschik (A), Model = VW Golf 5 }
* { Name = Michael Kloss (B), Model = Vw Golf 6 }
*/

Very, very nice! And very simple!

LINQ to Entities does automatically join each Person p with it’s cars c in p.Cars. In the further restrictions, ordering or the select-statement you have access to a joined pair of a Person p and a Car c.

This results in following SQL select statement:

SELECT 
[Project1].[C1] AS [C1], 
[Project1].[Name] AS [Name], 
[Project1].[Model] AS [Model]
FROM ( SELECT 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Model] AS [Model], 
    1 AS [C1]
    FROM  (SELECT 
      [AllPeople].[Id] AS [Id], 
      [AllPeople].[Name] AS [Name], 
      [AllPeople].[Age] AS [Age]
      FROM [dbo].[AllPeople] AS [AllPeople]) AS [Extent1]
    INNER JOIN (SELECT 
      [AllPeopleCars].[PersonId] AS [PersonId], 
      [AllPeopleCars].[Model] AS [Model], 
      [AllPeopleCars].[Id] AS [Id]
      FROM [dbo].[AllPeopleCars] AS [AllPeopleCars]) AS [Extent2] ON [Extent1].[Id] = [Extent2].[PersonId]
)  AS [Project1]
ORDER BY [Project1].[Model] ASC

Don’t ask me what the nested select statement and C1 is for, but else this is quite straight forward.

But, as you also can see, the two from statements result in a INNER JOIN. But what about ecologic people, as for example my colleague Hergen?

“Also list people without cars”

On the SQL side we just have to use a LEFT OUTER JOIN instead of the current INNER JOIN. But how to do that with LINQ?

LINQ does natively support joins, but doesn’t offer a direct keyword that would let you specify how the join should be mapped to a relational structure.

But there is a simple trick, that semantically should do the same thing:

from p in model.AllPeople
from c in p.Cars.DefaultIfEmpty()
orderby c.Model
select new { p.Name, Model = c != null ? c.Model : null };

DefaultIfEmpty() should just pretend a collection with a single type default of the expected type, default(Car)==null in this case and return it as single collection item, if the base collection p.Cars is empty.

It depends on the LINQ implementation, whether Model on c (which can be null) is accessible directly (as in SQL) or has to be checked. Since this code is never really compiled and ran, but instead converted to an Expression Tree and passed into the specific LINQ implementation for interpretation, it could gracefully do the null-checking internally – which some implementations do.

So, LINQ would let you express it this way. But the LINQ implementation for Entity Framework (LINQ to Entities) does not support DefaultIfEmpty(). There is a lot of information out there on left outer joins in LINQ to Entities, but nothing that really works. You know a solution? Please, tell me!

So here we have to switch to Entity SQL (Object Query). We could also use the Query Builder Methods, but lets save that for later.

var query = model.CreateQuery<IDataRecord>(
    "SELECT p.Name, c.Model FROM AllPeople as "
  + "p OUTER APPLY p.Cars as c ORDER BY c.Model");

var casted = from item in query.ToArray() /* executes here */
  select new {
    Name = item.GetString(0),
    Model = (item.IsDBNull(1) ? null : item.GetString(1))
  };

/* Results
* { Name = Hergen Oltmann (A), Model = }
* { Name = Michael Kloss (B), Model = Mercedes E350 CDI Coupé }
* { Name = Lars Corneliussen (B), Model = Skoda Oktavia }
* { Name = Lars Corneliussen (B), Model = VW Fox }
* { Name = Michael Jendryschik (A), Model = VW Golf 5 }
* { Name = Michael Kloss (B), Model = Vw Golf 6 }
*/

Now we got what we wanted. The SQL query send to the server just has a LEFT OUTER JOIN instead of the INNER JOIN.

But we had to refactor the whole query and missed all the convenience LINQ to SQL offers for this simple requirement. Since Object Query has no support for anonymous types, we also have to access the result set in a generic manner, which throws us back to, say, SqlDataReader.

The story goes on. Lets forget people without cars for now and try some other real world restrictions.

“Lets list all people driving Volkswagen”

Back to our favorite LINQ-syntax:

from p in model.AllPeople
where p.Cars.Any(c => c.Model.Contains("VW"))
select p;

/* Results
* { Name = Michael Jendryschik (A), Age = 42 }
* { Name = Lars Corneliussen (B), Age = 26 }
* { Name = Michael Kloss (B), Age = 33 }
*/

The results are what we expected, and this is the SQL query being executed:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[Age] AS [Age]
FROM (SELECT 
      [AllPeople].[Id] AS [Id], 
      [AllPeople].[Name] AS [Name], 
      [AllPeople].[Age] AS [Age]
      FROM [dbo].[AllPeople] AS [AllPeople]) AS [Extent1]
WHERE  EXISTS (SELECT 
    cast(1 as bit) AS [C1]
    FROM (SELECT 
      [AllPeopleCars].[PersonId] AS [PersonId], 
      [AllPeopleCars].[Model] AS [Model], 
      [AllPeopleCars].[Id] AS [Id]
      FROM [dbo].[AllPeopleCars] AS [AllPeopleCars]) AS [Extent2]
    WHERE ([Extent1].[Id] = [Extent2].[PersonId]) AND ((CAST(CHARINDEX(N'VW', [Extent2].[Model]) AS int)) > 0)
)

Instead of doing a sub-query we could also easily use a join in combination with distinct. That doesn’t really make a difference.

But do you see this ugly part there? ((CAST(CHARINDEX(N'VW', [Extent2].[Model]) AS int)) > 0) Well it works for a demo, but usually what we really want Contains to map to is a LIKE, right.

Back to the real customer; do you know those DataGrids with filter fields beneath each title column? Well lets pretend someone enters “M” for filtering the resulting rows by name.

“Give me only those people driving Volkswagen, whose names start with ‘M’“

Since LINQ to Entities neither supports StartsWith nor Like, we have to switch to Object Query again.

This time, we’ll use the query builder methods. At the same time we also replace the CHARINDEX for “VW” to a proper LIKE.

var query = model.AllPeople
  .Where("EXISTS(SELECT c FROM it.Cars as c "
       + "WHERE c.Model LIKE '%VW%')")
  .Where("it.Name LIKE @pattern",
          new ObjectParameter("pattern", "m%"));

/* Results
* { Name = Michael Jendryschik (A), Age = 42 }
* { Name = Michael Kloss (B), Age = 33 }
*/

This results into following SQL statement:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[Name] AS [Name], 
[Extent1].[Age] AS [Age]
FROM (SELECT 
      [AllPeople].[Id] AS [Id], 
      [AllPeople].[Name] AS [Name], 
      [AllPeople].[Age] AS [Age]
      FROM [dbo].[AllPeople] AS [AllPeople]) AS [Extent1]
WHERE ( EXISTS (SELECT 
    cast(1 as bit) AS [C1]
    FROM (SELECT 
      [AllPeopleCars].[PersonId] AS [PersonId], 
      [AllPeopleCars].[Model] AS [Model], 
      [AllPeopleCars].[Id] AS [Id]
      FROM [dbo].[AllPeopleCars] AS [AllPeopleCars]) AS [Extent2]
    WHERE ([Extent1].[Id] = [Extent2].[PersonId]) AND ([Extent2].[Model] LIKE '%vw%')
)) AND ([Extent1].[Name] LIKE 'm%')

I hope my example queries were able to give you an overview over the state of LINQ to SQL and its current limitations.

Resources on EF

http://www.amazon.com/Programming-Entity-Framework-Julia-Lerman/dp/059652028X

Inheritance in EF

Entity Data Model Inheritance (Application Scenarios)

ADO.NET team blog : Inheritance in the Entity Framework

My Advice

If you have to stick with Entity Framework, use ObjectQuery and Entity SQL and avoid using LINQ to Entities except you know what you are doing. Maybe you should also look into some community tools around EF then.

If you haven’t chosen yet, or if you still have the chance to get out of the tight spot, consider other O/R-mappers as for example NHibernate, which we also switched to later in the project.

I’ll show how we solved our problems using NHibernate in a follow-up post soon.

Read Full Post »

We love being productive. And there are tons of generic problems that we solve far too often. The .NET Base Class Library has plenty of functionality (compared to Java w/o Apache.Commons). But still there is much missing.

So, every developer has tons of snippets in his backyard, from where he digs up and copy-pastes class by class, method by method. Then, from time to time, in the name of reuse, we package those utilities in libraries called *.Common or *.Utils, and put them in our toolbox. Some of us (as a species) then publish their util-libraries as open source: Among them Rhino.Commons, Umbrella, Magnum and many more.

The cost of dependencies

The cost of an dependency is high. If you just need that little thing, but introduce a dependency to a big ball of (unrelated) mud – you’re better off copy-pasting exactly what you need. But event that is hard, because if you start writing utilities, then your utilities tend to depend on each other.

Good reads on this topic:

But still…

But still we do not want to reinvent the wheel on every project. So what to do?

Options

Lets just shortly list the options we have for reusing generic code – besides creating huge utility libraries:

  • Copy-paste
  • Creating very specific libraries: but who want’s the overhead of a DLL?
  • … IL-merge those very specific libraries
  • Utilize .NET modules; those are smaller than an assembly and can be linked into any assembly – that is what ILmerge does. But there is no tooling support for .NET modules in Visual Studio…

I think there is just one option left: Single-file distributions with utility-classes, that can be included as source.

But how to distribute them? How to version? How to upgrade?

Then, how to maintain them? Manual download, copy-paste? In times of NPanday and Nuget? Not really.

Minimods

With this in mind I started off something I’ll call Minimod for now. It is a rather small module, containing of source code only, that can be installed into any of your C# assemblies.

I’ll write more on how to create and publish a Minimod later (hopefully in combination with NPanday).

Definition

A Minimod is defined as follos:

  • it must consist of one file and be very specific (no StringExtensionsMinimo, LinqExtensionsMinimod, or MyUtilMinimod please!!)
  • Each Minimod must be in it’s own namespace in order to avoid extension-method conflicts.
  • A Minimod should only depend on .NET BCL or other Minimods

I also want tool-support for integrating it, as well as upgrade/remove.

Proof of Concept

I just started bundling some utilities in classes and created simple Nuget-Packages. This makes it very easy to install and upgrade the files.

image

Then I published those to the Nuget Gallery.

image

When installing, a file will be created in the subdirectory Minimods. I named it *.Generated.cs, because that will prevent ReSharper from complaining about things.

image

Preview of the imported file. Namespace does not fit (see issues).

image

Now we use them:

using Minimod.NestedDictionary;
using Minimod.PrettyText;
using Minimod.PrettyTypeSignatures;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            var width = 22;
            Console.WindowWidth = width;

            var minimods = "Minimods are great! Go get them at Nuget.org, just by searching for 'minimod'.";

            Console.WriteLine(
                minimods
                .ShortenTo(width)
                );

            Console.WriteLine();

            Console.WriteLine(
                minimods
                .WrapAt(width)
                .JoinLines());

            var listPerKey =
                new Dictionary<string, List<string>>();

            Console.WriteLine();

            Console.WriteLine(
                listPerKey.GetType()
                .GetPrettyName()
                .ShortenTo(width));

            listPerKey.EnsureValueFor("key1");
            listPerKey.AddToCollection("key2", "one");
            listPerKey.AddToCollection("key2", "two");

            Console.WriteLine();

            Console.WriteLine("key1: " +
                String.Join(", ", listPerKey["key1"]));

            Console.WriteLine("key2: " +
                String.Join(", ", listPerKey["key2"]));

            Console.ReadKey();
        }
    }
}

The result

image

Still to be considered

  • Namespace should maybe be adjusted to the target-projects namespace + “.Minimods”? Or is it great having *.Minimod for all of them?
  • Id, description and versioning is all done manually now – want to automate this.
  • Haven’t tried with dependencies yet, but that should work.
  • Planning to use NPanday to automate the process of releasing and publishing Minimods ([#NPANDAY-372] Integrate with NuGet and NuGet Gallery (nuget.org))

What do you think? I’d be happy to get Feedback on the process!

I’ll also hopefully keep posting more Minimods.

Current source code is here: moved to minimod/minimods at GitHub (from Braindrops.MiniMods at GitHub)

Read Full Post »

Older Posts »

Follow

Get every new post delivered to your Inbox.

Join 433 other followers