Archive

Author Archive

Automated Build – Getting better

May 10th, 2010 No comments

A while ago I wrote a post, describing how to setup a continues build system using CruiseControl.Net. In that post I showed how to get your project ready be continuously being build.

It’s all about improvement

That was a big step towards continues improvement in the software developing lifecycle. The next big thing is to be always up-to-date with the quality of your software and to make sure that all those bugs get fixed real soon.

To accomplish this, I created a unit-test project for my application. This can be used to do test-driven development or just to test the code you just wrote. However – you basically want to run this code whenever you change something and keep an close eye on the red-green status-icons. Whenever I make some modifications this should not affect existing features.

This means, we have to run the rest on a regular basis. This is especially important when we want to deliver some bits. We definitely want to make sure, that all test pass before we ship something.

This is where our continues integration server comes back into the game. We already have this setup to make a new build of the project whenever something changes – so now all we need to do is to make sure all our unit-tests are being run as well.

Updating the project

First of, we need to extend our NAnt build-file. We add a new target, which will run the unit-tests. I prefer to use Gallio to run my unit-tests, because this allows me to use a big variety of unit-testing-frameworks without changing the execution runtime.

<target name="run-tests" description="Run Unit tests">

    <loadtasks assembly="C:\Program Files\Gallio\bin\Gallio.NAntTasks.dll"/>
    <trycatch>
      <try>
        <gallio report-types="Xml-Inline;Html"
                report-directory="testresults"
                report-name-format="Pizza.Testing.dll-results"
                runner-type="NCover"
                failonerror="true">
          <runner-property value="NCoverCoverageFile='testresults\coverage.xml'" />
          <runner-property value="NCoverArguments='//a Pizza.Testing'"/>
          <files refid="fileset_test_assemblies">
            <include name="Pizza.Testing.dll" />
          </files>
        </gallio>
      </try>
      <catch property="failure">
        <echo message="At least one test failed: ${failure}"/>
      </catch>
    </trycatch>

    <loadtasks assembly="C:\Program Files\NCoverExplorer\NCoverExplorer.NAntTasks.dll"/>
    <echo message="Running NCoverExplorer report generation ..."/>
    <ncoverexplorer program="C:\Program Files\NCoverExplorer\NCoverExplorer.console.exe"
                    reportType="3"
                    xmlReportName="testresults\coveragereport.xml"
                    satisfactoryCoverage="80">
      <fileset>
        <include name="testresults\coverage.xml"/>
      </fileset>
    </ncoverexplorer>

</target>

This target will run all tests in the Pizza.Testing assembly of the project. Furthermore all test-results are being written to a file called Pizza.Testing.dll-results.xml.

Finally I also run the NCoverExplorer to get a nice summary of my code coverage. You might notice the runner-type=NCover, which causes Gallio to run all unit-tests within the NCover context. This way we get also some nice numbers of which code is actually covered by unit-tests.

Doing it on the server

After getting the build-file up and running we can make some adjustments to the project-configuration within CCNet (ccnet.config). Obviously we need to make sure, that the newly created target is being called during the build-process. So that’s fairly simple.

<nant description="main build">
    <executable>d:\nant\bin\NAnt.exe</executable>
    <buildFile>d:\ccnet\repositories\Pizza\Source\default.build</buildFile>
    <targetList>
      <target>Compile run-tests</target>
    </targetList>
 </nant>

But we also need to make sure, we collect all data, that is being recorded during the tests (like the test results). Since this is being recorded in a separate xml file, we need to merge this file into the main build-log, which is being maintained by CCNet.

<publishers>
    <merge>
        <files>
            <file>.\source\build\release\test-results\coverage*.xml</file>
            <file>.\source\build\release\test-results\*-results.xml</file>
        </files>
    </merge>
  <xmllogger />
  <statistics />
  <modificationHistory />
</publishers>

Showing what was done

So now we have the tests automated, and setup to run with each build. The final step is to show the test-results in the project dashboard.

For the results to show up, we have to modify the dashboard configuration in that respect, that the results are being rendered into HTML. So far they have only been merged into the build-file log.

This is being done by adding new XSL-transformations to the configuration (dashboard.config). These are part of the Gallio-package.

<xslReportBuildPlugin description="Gallio Test Report"
  actionName="GallioTestReport"
  xslFileName="gallio\xsl\Gallio-Report.ccnet-details.xsl" />
<xslReportBuildPlugin description="Gallio Test Report (Condensed)"
  actionName="GallioTestReportCondensed"
  xslFileName="gallio\xsl\Gallio-Report.ccnet-details-condensed.xsl" />
<xslReportBuildPlugin description="NCoverExplorer Report"
  actionName="NCoverExplorerBuildReport"
  xslFileName="xsl\NCoverExplorer.xsl" />
<gallioAttachmentBuildPlugin />

After that we can have a look on how many tests succeed and how many failed. The display looks just like the Gallio Runner.

ccnet_gallio

ccnet_ncoverexplorer

Categories: Programming Tags: , ,

Pimp my Studio

May 6th, 2010 No comments

If the vanilla look of Visual Studio doesn’t do it for you, check out studiostyles.net. Here you’ll find a huge amount of visual styles for Visual Studio 2008 and 2010.

BTW: my current favorite theme is Desert Nights Reloaded :) – even though I doesn’t make use of my beloved Envy Code R font …

Categories: Others Tags: , ,

Work more efficient with Visual Studio

April 26th, 2010 No comments

Sara Ford started in 2007 to publish daily tips and tricks on working with Visual Studio 2008 on her blog. Now Zain Naboulsi took over and is also presenting tips on working with Visual Studio 2010.

Categories: .Net Tags: ,

Adding Attachments to SharePoint blogs

April 23rd, 2010 No comments

While SharePoint 2007 does offer a blog-template, this is actually quite minimalistic. Even though you can usually add attachments to every list item in sharepoint, this is not possible for blog posts.

Well, actually, attachments are enabled for blog posts, and if you’re using an editor such as Windows Live Writer all images and files are being added as attachments to the current post. But this just isn’t possible if you’re stuck with the web-editor for writing new posts.

So I did some digging on what’s needed to get SharePoint to offer attachments for blog posts.

First of all you should be aware, that you’re going to modify some files dear and near to SharePoint – this might not always be the recommended way :)

OK, let’s get started. Since we already noticed that attachments are enabled on the list of posts, we somehow need to get this darn button in the toolbar to appear.

Since the blogging feature is built-in into SharePoint it’s view definition is found in the DefaultTemplates.ascx within the %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\12\Template\ControlTemplates. Within this file are a whole lot of Rendering-Templates defined. Based on the existing BlogForm Template I created my own Template called BlogFormExt.

<SharePoint:RenderingTemplate ID="BlogFormExt" runat="server">
    <Template>
        <SPAN id='part1'>
            <SharePoint:InformationBar runat="server"/>
            <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbltop" RightButtonSeparator="&nbsp;" runat="server">
                    <Template_RightButtons>
                        <SharePoint:SaveAsDraftButton Text="<%$Resources:wss,tb_saveasdraft%>" runat="server"/>
                        <SharePoint:PublishButton Text="<%$Resources:wss,tb_publish%>" runat="server"/>
                        <SharePoint:GoBackButton runat="server"/>
                    </Template_RightButtons>
            </wssuc:ToolBar>
            <SharePoint:FormToolBar runat="server"/>
            <p><a href="javascript:UploadAttachment();">Attach Me!</a></p>
            <TABLE class="ms-formtable" style="margin-top: 8px;" border=0 cellpadding=0 cellspacing=0 width=100%>
            <SharePoint:ChangeContentType runat="server"/>
            <SharePoint:FolderFormFields runat="server"/>
            <SharePoint:ListFieldIterator runat="server"/>
            <SharePoint:ApprovalStatus runat="server"/>
            <SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
            </TABLE>
            <table cellpadding=0 cellspacing=0 width=100% style="margin-top: 10px;"><tr><td class="ms-formline"><IMG SRC="/_layouts/images/blank.gif" width=1 height=1 alt=""></td></tr></table>
            <TABLE cellpadding=0 cellspacing=0 width=100% style="padding-top: 7px"><tr><td width=100%>
            <SharePoint:ItemHiddenVersion runat="server"/>
            <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&nbsp;" runat="server">
                    <Template_Buttons>
                        <SharePoint:InitContentType runat="server"/>
                        <SharePoint:CreatedModifiedInfo runat="server"/>
                    </Template_Buttons>
                    <Template_RightButtons>
                        <SharePoint:SaveAsDraftButton Text="<%$Resources:wss,tb_saveasdraft%>" runat="server"/>
                        <SharePoint:PublishButton Text="<%$Resources:wss,tb_publish%>" runat="server"/>
                        <SharePoint:GoBackButton runat="server"/>
                    </Template_RightButtons>
            </wssuc:ToolBar>
            </td></tr></TABLE>
        </SPAN>
        <SharePoint:AttachmentUpload runat="server"/>
    </Template>
</SharePoint:RenderingTemplate>

Important are the two highligthed lines. The first line adds a link to display a dialog to upload an attachment, the orher line adds the actual code for the dialog and stuff.

OK, so now we habe our new layout in place, that allows us to add attachments to new posts. Next we need to alter our blog to make use of this new template definition.

So using SharePoint-Designer open up the blog and navigate got the posts list. Open up the NewPost.aspx and find the webpart-element in the code view. There should be a line like

<TemplateName xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">BlogForm</TemplateName>

which you wand to edit to

<TemplateName xmlns="http://schemas.microsoft.com/WebPart/v2/ListForm">BlogFormExt</TemplateName>

This will use our new template-definition instead of the build-in template view.

This is basically all you need to do – well you also might want to edit the EditPost.aspx to use a template which enables the upload of new attachments; but I leave that to you.

Oh – one final note: this enables uploading attachments to a blog-post, but the attachments are not automatically displayed for e.g. as a list of items in the end of the post. You will have to add the links to the attachments in your post manually!.

Strange behaviors in SharePoint deployment

April 22nd, 2010 No comments

Today I had some really strange experiences while deploying some SharePoint application using a custom build WSP file.

First, I tried to re-deploy an existing solution, but that didn’t seem to succed. At least my SharePoint site replied with a “Service unavailable” notice. So I though, I should retract the solution – maybe someting in me updated solution broke my SharePoint site.

So doing a

stsadm –o retractsolution –name myapp.wsp –allcontenturls –immediate

also just failed on me. So next I was stuck. I couldn’t neither delete the solution nor retry to retract the solution because everytime I got the message, that another job is currently retracting this solution. This is why I couldn’t do anything at the moment. But what now? It didn’t seem like the was any other job running.

So I gathered a list of all running deployments using

stsadm –o enumdeployments

and then

stsadm –o canceldeployment –id 

to actually cancel the running deployment. After that I could issue

stsadm –o deletesolution –name myapp.wsp –force

This actually remove the solution – but I had to find, that this wasn’t the cause for my “service unavailable”. So all this for nothing!

The strange thing about that is, that only one out of a dozen websites was not working. Then it strike me – looking at the IIS admin I found, that the app-pool associated with this SharePoint site was stopped – restarting the app-pool solved my “service unavailable” immediately.

Categories: SharePoint Tags:

Chuck Norris and SharePoint 2010

April 9th, 2010 1 comment

Top ten facts about Chuck Norris and SharePoint 2010:

  1. Chuck Norris never starts an Approval workflow in SharePoint. Chuck doesn’t need approval.
  2. Chuck Norris isn’t afraid to customize, one look and SharePoint runs at peak performance.
  3. Putting Chuck Norris in the SharePoint Visitors group is futile. Chuck always has Full Control.
  4. Chuck Norris doesn’t have a SharePoint Disaster Recovery Plan. He doesn’t recover data, only hostages.
  5. Chuck does not subscribe to Alerts. He knows what is happening before it happens.
  6. Chuck Norris IS the Governance Plan.
  7. In SharePoint 2010, the Farm Administrators group is being renamed to ‘Chuck’s Group’.
  8. Chuck Norris never get’s unexpected errors with SharePoint because he is always ready for everything.
  9. Chuck Norris doesn’t prepare for SharePoint 2010. SharePoint 2010 prepares for him.
  10. SharePoint 2010 was a Chuck Norris idea.

chucknorris

Categories: SharePoint Tags:

Performance boundaries of SharePoint

March 27th, 2010 No comments

Once in a while the same question keeps poping up: how many items can be stored in a list? How many documents can be stored in a document library?

Microsoft published an overview from a technical perspective, giving guidelines as well as showing the impact on performance when the number of sites or items increase.

Categories: SharePoint Tags:

Localization using NHibernate and filters

March 13th, 2010 No comments

After I received some feedback on my post on filtering with NHibernate, I starting thinking on how to leverage the filter capabilities of NHibernate to create a system for creating localized applications. While the previous post already considered using filters for multi-language apps, there was some criticism.

When I want to localize a pizza I had to create a new record in the database. One of the first drawbacks was the fact, that the ID of the pizza is not unique anymore, since each pizza exists for each language. Well, this is actually just a matter of “adjusting” the data model a little bit. You could just create some internal ID for each pizza as the primary key or you create a composite key based on the ID and the locale-code.

A bigger problem is the fact, that you will have to duplicate all the data, which isn’t actually changing for each pizza, such as the price.

The new model

A better data model could look like this:

PizzaModel

Some explanation: a pizza has always a list of toppings. Pizzas as well as toppings have name, which should be localized. This name can exists in various languages for a pizza. The class LocalizableBase adds a list of strings, which contains all localized strings.

This way we don’t have to store language invariant data redundant in the database.

The usage

OK, since we have our revised model, the actual usage is straight-forward.

// create toppings
var pilze = new Entities.Topping { InternalName = "Pilze" };
pilze.AddString("de","Pilze");
pilze.AddString("en","Mushrooms");
_session.Save(pilze);

var salami = new Entities.Topping() {  InternalName = "Salami" };
salami.AddString("de","Salami");
salami.AddString("en","Pepperoni");
_session.Save(salami);

var kaese = new Entities.Topping() {InternalName = "Käse"};
kaese.AddString("de","Käse");
kaese.AddString("en","Cheese");

// create pizza
var funghi = new Entities.Pizza()
{
    Price = 10,Costs = 5,Toppings = {pilze}
};
funghi.AddString("de", "Funghi");
funghi.AddString("en", "Mushroom Heaven");
_session.Save(funghi);

var peperoni = new Entities.Pizza()
{
    Price = 11,
    Costs = 6.5,
    Toppings = { salami,kaese }
};
peperoni.AddString("de", "Salami++");
peperoni.AddString("en", "Peperoni++");
_session.Save(peperoni);

At first we create some toppings. Each topping has an internal, language-invariant name. Using AddString (from LocalizeableBase) we can add strings for a certain language. The same applies for pizza.

In order to get a pizza, we just create a simple query.

[Test]
public void CanGetLocalizedPizza()
{
    _session.EnableFilter("PizzaLocaleFilter").SetParameter("myLocale", "en");
    var pizzaList = _session.CreateCriteria<Pizza.Entities.Pizza>()
        .List<Entities.Pizza>();

    Assert.That(pizzaList,Has.Count.EqualTo(2),"number of pizza");
    Assert.That(pizzaList[0].Name, Is.EqualTo("Mushroom Heaven"));
    Assert.That(pizzaList[1].Name, Is.EqualTo("Peperoni++"));

    Assert.That(pizzaList[0].Toppings, Has.Count.EqualTo(1),"number of toppings");
    Assert.That(pizzaList[0].Toppings[0].Name,Is.EqualTo("Mushrooms"),"name of topping");
}

As the above sample shows, we just have to define our filter once (!). In the actual query we don’t have to deal with the filtering anymore, this is all being handled by NHibernate.

The implementation

Finally I would like who this is all accomplished. At first we store all localizable strings in a separate table. This table contains strings for toppings as well as for pizzas. This table is being mapped to a class, which is used by LocalizableBase.

<class name="LocalicedString" table="LocalicedStrings">
  <id name="Id">
    <generator class="identity"/>
  </id>
  <property name="ObjectType"/>
  <property name="Locale"/>
  <property name="Text"/>
</class>

The property ObjectType stores to which entity this string actually belongs to. The value for this property is being determined in the method AddString in LocalizableBase. This way the pizza entity doesn’t have to take care about setting the property to the correct value. Besides the object-type, we also store the id of the actual object. Since this id is not directly being used, we don’t need to map it to the database (at least not at this point; we’ll see that later).

/// <summary>
/// base class to supply localizablity to entities
/// </summary>
public abstract class LocalizableBase
{
    /// <summary>
    /// Initializes a new instance of the <see cref="LocalizableBase"/> class.
    /// </summary>
    public LocalizableBase()
    {
        Strings = new List<LocalicedString>();
    }

    /// <summary>
    /// a list of all localized strings
    /// </summary>
    public virtual IList<LocalicedStrings> Strings { get; private set; }

    /// <summary>
    /// adds a new string to the list of <see cref="Strings"/>
    /// </summary>
    /// <remarks>along with the text and the locale, the object to which
    /// this text is associated is also being stored</remarks>
    /// <param name="locale">the locale of the text</param>
    /// <param name="text">the text to store</param>
    public virtual void AddString(string locale, string text)
    {
        Strings.Add(new LocalicedString
                        {
                            Locale = locale,
                            Text = text,
                            ObjectType = GetType().ToString()
                        });
    }
}

OK, now we need the entities for pizza and topping as well. This is actually nothing earth-rocking. The property Name returns always the first localized string that was found for the entity. If no localized string could be found, we just return an empty string.

/// <summary>
/// Business Entity representing a pizza
/// </summary>
public class Pizza : LocalizableBase
{
    /// <summary>
    /// Initializes a new instance of the <see cref="Pizza_old"/> class
    /// </summary>
    public Pizza()
    {
        Toppings = new List<Topping>();
    }

    /// <summary>
    /// gets the internal, unique id of this pizza
    /// </summary>
    /// <value>The id.</value>
    public virtual int Id { get; private set; }

    /// <summary>
    /// gets the localized name of the pizza
    /// </summary>
    public virtual string Name
    {
        get { return Strings.Count >= 1 ? Strings[0].Text : string.Empty; }
    }

    /// <summary>
    /// gets or sets the toppings, which are being used by the pizza
    /// </summary>
    public virtual IList<Topping> Toppings { get; private set; }

    /// <summary>
    /// selling price for this pizza
    /// </summary>
    public virtual double Price { get; set; }

    /// <summary>
    /// gets or sets the costs to produce this pizza
    /// </summary>
    public virtual double Costs { get; set; }
}

/// <summary>
/// Business Entity representing a pizza-topping
/// </summary>
public class Topping : LocalizableBase
{
    /// <summary>
    /// gets the internal, unique id of this topping
    /// </summary>
    /// <value>The id.</value>
    public virtual int Id { get; private set; }

    /// <summary>
    /// gets or sets internal name of this topping - this is language invariant!
    /// </summary>
    public virtual string InternalName { get; set; }

    /// <summary>
    /// gets the localized name of the topping
    /// </summary>
    /// <value>The name.</value>
    public virtual string Name
    {
        get { return Strings.Count >= 1 ? Strings[0].Text : string.Empty; }
    }

    /// <summary>
    /// supplier, from where this topping is being bought
    /// </summary>
    public virtual string Supplier { get; set; }
}

The clue to this solution is again the usage of NHibernate filters, in order to get the strings for the desired language. For that purpose we filter for the desired locale. In this mapping we also find the ItemId property, which was kinda missing in the LocalizedStrings mapping. The ItemId refers to the Id of the item, to which this string actually belongs. In combination with the ObjectType this should be unique.

<class name="Pizza" table="Pizzas">
  <id name="Id">
    <generator class="identity" />
  </id>
  <property name="Price"/>
  <property name="Costs"/>

  <bag name="Strings" table="LocalicedStrings"
       cascade="all" fetch="join"
       where="ObjectType='Pizza.Entities.Pizza'">
    <key column="ItemId" />
    <one-to-many class="LocalicedString"/>
    <filter name="PizzaLocaleFilter" condition=":myLocale = Locale"/>
  </bag>

  <bag name="Toppings" table="PizzaToppings" cascade="all">
    <key column="PizzaId" />
    <many-to-many column="ToppingId" class="Topping" />
  </bag>
</class>

Besides the filtering to a certain language, we also only want to get strings for the current ObjectType. This is done, by specifying a where-clause in the bag-definition. This way we only get strings for pizza.

While this removes the actual need to deal with the ObjectType in the query, we have to specify it in the mapping – well nothing’s perfect. If you already have an application with a lot of existing queries, this might be a better approach.

Just for the hack of it: this is the SQL being send to the database for the little UnitTest query:

SELECT this_.Id as Id4_1_, this_.Price as Price4_1_, this_.Costs as Costs4_1_, strings2_.ItemId as ItemId3_, strings2_.Id as Id3_, strings2_.Id as Id7_0_, strings2_.ObjectType as ObjectType7_0_, strings2_.Locale as Locale7_0_, strings2_.Text as Text7_0_
FROM Pizzas this_ left outer join
    LocalicedStrings strings2_ on
        this_.Id=strings2_.ItemId and
        @p0 = strings2_.Locale and
        (strings2_.ObjectType='Pizza.Entities.Pizza')
;@p0 = 'en'

SELECT toppings0_.PizzaId as PizzaId1_, toppings0_.ToppingId as ToppingId1_, topping1_.Id as Id6_0_, topping1_.InternalName as Internal2_6_0_
FROM PizzaToppings toppings0_ left outer join
    Toppings topping1_ on
        toppings0_.ToppingId=topping1_.Id
WHERE toppings0_.PizzaId=@p0
;@p0 = 1

SELECT strings0_.ItemId as ItemId1_, strings0_.Id as Id1_, strings0_.Id as Id7_0_, strings0_.ObjectType as ObjectType7_0_, strings0_.Locale as Locale7_0_, strings0_.Text as Text7_0_
FROM LocalicedStrings strings0_
WHERE  @p0 = strings0_.Locale and
    (strings0_.ObjectType='Pizza.Entities.Topping') and
    strings0_.ItemId=@p1
;@p0 = 'en', @p1 = 1
Categories: .Net Tags:

IFilter for TIFF

March 3rd, 2010 No comments

Windows Server 2008 R2 comes OOTB with an IFilter, which allow the indexing of TIFFs. During the indexing the IFilter performs an OCR to recognize the actual content of the TIFF for the index.

This combined with a corresponding scanner introduces a small-sized DMS, where you can scan paper based documents to a document-library and let them being index and thus fully searchable by SharePoint.

Categories: SharePoint Tags: ,

Modifiy any page within SharePoint

February 27th, 2010 No comments

There is alway something new to discover. Usually when you want to edit a page in SharePoint you just hit “Website actions” “edit page”. But certain pages don’t offer to edit themself, such as the edit-form for list-items. So what?

Just append “toolpaneview=2” to the address of the currently visible page; and magically you’ll see the WebPart-Editor-Pane, which allows to edit the current page. This way you can literally edit every page in SharePoint.

Categories: SharePoint Tags: