Compiling cshtml from visual studio tools menu

10. May 2016 15:46 by martijn in

We all know and love the MvcBuildViews settings you can add to your project to enable compilation of views during build. But sometimes this does not give you the desired result and it slows down your build considerably. An alternative is to invoke the view compilation on demand by configuring it as a external tool.

This is actually quite easy to do and integrates nicely with VS. In the screenshot below you see how to configure an external tool for this. The only thing that is not in the screenie is the path to the aspnet_compiler.exe which is invoked. The path i have is C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_compiler.exe but this obviously depends on the version of .net your are using. 

 

To invoke it just select your web project and click Tools -> Compile views. The cool thing is that VS opens the file with the error once you doubleclick a line.  Sweet :)

 

using jQuery File Ajax Upload plugin with ASP.NET

25. March 2015 21:37 by martijn in jQuery, jquery.fileuploader

Looking at the jquery fileupload plugin I noticed there wasn't a decent example of how to get it working in a asp.net webforms application. So I decided to share my little simple sample project with you. 

 

The project features:

  1. Selection of a file
  2. A separate upload button
  3. A progress bar

  

The project uses:

  1. Jquery file uploader https://blueimp.github.io/jQuery-File-Upload/
  2. Bootstrap
  3. Jquery 1.9.1
  4. Jquery UI for the widget (this seems a bit heavy but the demo breaks i
  5. A simple ashx handler for the server side

The ashx handler is very basic and you should probably expand it. I found some nice resources here but the project was not included for download. 

Download it here

UploadSample.zip (2.27 mb)

Debugging log4net

14. March 2015 19:03 by martijn in log4net

Log4net is a great tool but it can be a bit tricky to get working. Adding a debug appender that logs to the visual studio output can be of great help. You can debug log4net by attaching the log4net DebugAppender:

Add a log4net app setting in your app.config file:

<appSettings>

<!-- log4net configuration when running in debug mode. -->

<add key="log4net.Internal.Debug" value="true"/>

</appSettings>

Add a debug appender in the log4net config:

<appendername="DebugAppender" type="log4net.Appender.DebugAppender">

<immediateFlush value="true"/>

<layout type="log4net.Layout.SimpleLayout"/>

</appender>

Finally add the appender to the log4net config root:

<root>
<level value="ALL"/>
<appender-ref ref="DebugAppender"/>
</root>

Running SOAP UI tests from MsTest

13. March 2015 13:37 by martijn in .net, mstest, soapui

Recently I have been working in a project in which the tester used a tool called Soap UI. SoapUI makes it easy to create xml based test for services. Being a big fan of Continuous Integration I thought it would be cool to include SoapUI in our CI build cycle. Here's what you need to do to make it working

 

1. Install Soap UI

You can get a free version here. Take notice of the location in which it installs. For me this was : "C:\Program Files (x86)\SmartBear\SoapUI-4.6.4". I put this in the app.config of my test project.

2. Create a SoapUI project. 

Start up your SoapUI and go File->New Project. Point it to the wsdl of the service you want to test and let it create a testsuite. 

 

 

3. Add the Soap UI project to your MsTest project

In SoapUI right click save-project as on the project node. Save your xml file into a unit test project and include the xml in your project. Set Copy to Output Directory to "Copy if newer"

  

4. Running soap UI from MsTest

This is the tricky part. How can we get SoapUI to run our test from a UnitTest?? It turns out SoapUI has something called a Testrunner.bat which makes it relatively straightforward. Basically I create a testrunner proces in a unit test and redirect the output of SoapUI to the test output. Here's what the code looks like: (a zip of the project is included below). 

        /// <summary>

       /// Runs soapUI test named testName

        /// </summary>

        private void RunSoapUItest(string soapProject, string testSuiteName, string testName)

        {

            const string fileName = "cmd.exe";

            var soapProjectFileName = Path.GetFullPath(soapProject);

            var arguments = string.Format("/C testrunner.bat -s\"{0}\" -c\"{1}\" \"{2}\" ", testSuiteName, testName, soapProjectFileName);

 

            //for me this is C:\Program Files (x86)\SmartBear\SoapUI-4.6.4\bin

            var soapHome = System.Configuration.ConfigurationManager.AppSettings["SoapUIHome"];

            //start a process and hook up the in/output

            var proces = new Process

            {

                StartInfo = new ProcessStartInfo

                {

                    FileName = fileName,

                    Arguments = arguments,

                    WorkingDirectory = soapHome,

                    CreateNoWindow = true,

                    ErrorDialog = false,

                    RedirectStandardError = true,

                    RedirectStandardOutput = true,

                    UseShellExecute = false

                },

                EnableRaisingEvents = true

            };

            //pipe the output to console.writeline

            proces.OutputDataReceived += (sender, args) => Console.WriteLine(args.Data);

 

            //store the errors in a stringbuilder

            var errorBuilder = new StringBuilder();

            proces.ErrorDataReceived += (sender, args) =>

            {

                if (args != null && args.Data != null)

                {

                    errorBuilder.AppendLine(args.Data);

                }

            };

            proces.Start();

            proces.BeginOutputReadLine();

            proces.BeginErrorReadLine();

 

            proces.WaitForExit();//wait for SoapUI to finish

 

            //fail the test if anything fails

            var errorMessage = errorBuilder.ToString();

            if (!string.IsNullOrEmpty(errorMessage))

            {

                Assert.Fail("Test with name '{0}' failed. {1} {2}", testName, Environment.NewLine, errorMessage);

            }

        }

 5. Running a test per SoapUI testCase

A typical SoapUI project includes multiple testcases. To make each testcase run as a separate test we can use something called a DataSource attribute for the test. This attribute cause the test to run for every 'Row' in the XML.

[DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", "TestData\\test-service.xml", "testCase", DataAccessMethod.Random)]

Since every testCase is a row the makes every testCase run separately. You have to make sure you get xml deployed (I used a deploymentItem for that).

 

        /// <summary>

        /// Test Soap Stuff

        /// </summary>

        [TestMethod]

        [DeploymentItem(@"test-service.xml", "TestData")]

        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", "TestData\\test-service.xml", "testCase", DataAccessMethod.Random)]

        public void RunSoapServiceTest()

        {

            var testCaseName = TestContext.DataRow["name"].ToString();

            RunSoapUItest(@"TestData\test-service.xml", "BasicHttpBinding_ILicenseService TestSuite", testCaseName);

        }

I used the deploymentitems because I don't want absolute paths etc (I need the buildserver to handle this as well). Run the test and we get SoapUI output in Visual Studio / Build. Sweet :) To run this in a CI build you only need to install SoapUI on the buildserver and all should be well.

Here's the project:

MsTestSoapUI.zip (12.08 kb)

 

Happy Testing!

Post deployment Integration testing using TFS 2012 builds

16. December 2014 17:06 by martijn in tfs2012, testing

Why should I do integration testing?

Although I very much like unit-testing and frameworks like Moq they sometimes miss the big picture. You might have 99% code coverage and a green test suite only to find out later you messed up your environment because you did not register your new code in your dependency configuration or forgot to check-in some other configuration. Every little part of your code was tested but the sum did not work out. What if you could deploy to a test server and run your tests against this server? This is what post-deployment integration testing is about. The process below describes setting up a TFS build definition that does compile, test, deploy and integration-test. If any step fails the build fails. You can combine this with a gated check-in to make sure your environment never brakes. I would recommend to use the lab environment for this if you have set this up already : http://msdn.microsoft.com/en-us/library/hh191495.aspx. The method described here uses just a build controller and build agent.

Describing the process

The proces is a small modification of the normal gated-checkin process of TFS 2012. Only a integration-tests step is added.

Modifying the build template

To get integration testing we need to modify the build in two ways.

  1. Add a integration testing step to the build process. This is basically a copy of the normal unit-testing step with a slight modification. Instead of using the TestSpecs and DisableTest variabeles we use IntegrationTestSpecs and DisableIntegrationTest. I included the definition file for download below.
  2. Make sure your integration test are only run in the integration step and not in the regular unit-testing step. You can accomplish this by using categories for your integration tests. 

 

BuildTestDeployAndTestTemplate.xaml (117.36 kb)

Logging all WCF messages

16. September 2014 10:38 by martijn in

Just as a reminder. Here's how you log all messages for a wcf service. Copy & Paste into web.config.

<system.diagnostics>

    <sources>

      <source name="System.ServiceModel.MessageLogging" switchValue="Verbose">

        <listeners>

          <add name="messages"

          type="System.Diagnostics.XmlWriterTraceListener"

          initializeData="c:\logs\messages.svclog" />

        </listeners>

      </source>

    </sources>

  </system.diagnostics>

  <system.serviceModel>

    <diagnostics>

      <messageLogging

           logEntireMessage="true"

           logMalformedMessages="true"

           logMessagesAtServiceLevel="true"

           logMessagesAtTransportLevel="true"

           maxMessagesToLog="300000"

           maxSizeOfMessageToLog="200000"/>

    </diagnostics>

  </system.serviceModel>

Synching FileZilla settings using Dropbox

23. December 2013 11:28 by martijn in

I love Dropbox. One of the things it allows me to do is have setting files (keys/docs) synched accross my computers without any hassle. Combined with the sitemap.xml of FileZilla and I have easy access to my ftp accounts on all my machines. This howto describes how you can set up FileZilla / Dropbox so your sitemanager is stored on your DropBox.

So how can you set it up?

  1. First copy your FileZilla settings to your Dropbox. For me the settings files were stored in C:\Users\Martijn\AppData\Roaming\FileZilla. Copy the whole folder to your dropbox eg: C:\Users\Martijn\Dropbox\Filezilla
  2. Next we need to change the FileZilla defaults. There is a file called fzdefaults.xml.example in your FileZilla program files 'docs' folder (C:\Program Files (x86)\FileZilla FTP Client\docs). Copy this file to the folder above (C:\Program Files (x86)\FileZilla FTP Client\) and rename it to fzdefaults.xml. FileZilla will pick up this file and use it to find the other configuration files.
  3. Change the Config Location key to point to your Dropbox FileZilla folder of step 1

 

That's it! Happy synching!

Creating C# from XML

10. November 2013 10:56 by martijn in

Sometimes you have a piece of XML and quickly want to get the 'matching' c# classes so you can deserialize it. There is a website for this :)

http://code-w.com/Tools/Xml-to-Class-Generator

Just paste in your XML and get C# classes in return. Nice :)

 

Creating a simple logging Interceptor using NInject 3.0

8. October 2013 20:52 by martijn in .net, DRY, ninject

One of the really cool aspects of Depency Injection is the ability to add functionality without changing existing code. A typical example of this might be implementing INotifyPropertyChanged or logging method calls. Using NInject 3.0 Interceptors it is very easy to do this. The interceptor intercepts all calls to the resolved object and allows you to add logging or whatever code you want to run. In NInject 3.0 the methods you intercept do NOT have to be virtual as well :) So how to set it up...

Getting the right assemblies.

Using Nuget just get NInject.Extensions.Interception.Linfu. This will also setup NInject 3.0 and NInject.Extensions.Interception.

 

Creating the logging Interceptor

This is just a sample interceptor that logs using Console.Writeline. Normally you would call something like Log4Net or your preferred logging framework. Implementing IInterceptor means you have to implement a Intercept method. The Intercept method gets a invocation as a parameter. By invocation.Proceed() the original method gets called. The logger first logs the method being called and the arguments it is called with. After the invocation.Proceed() it logs the result of the method call. The interceptor is pretty simple and can certainly be improved by creating nicer more custom messages.

public class LoggingInterceptor : IInterceptor

    {

        public void Intercept(IInvocation invocation)

        {

            var methodName = invocation.Request.Method.Name;

            try

            {

                var parameterNames = invocation.Request.Method.GetParameters().Select(p => p.Name).ToList();

                var parameterValues = invocation.Request.Arguments;

 

                var message = string.Format("Method {0} called with parameters ", methodName);

                for (int index = 0; index < parameterNames.Count; index++)

                {

                    var name = parameterNames[index];

                    var value = parameterValues[index];

                    message += string.Format("<{0}>:<{1}>,", name, value);

                }

 

                //log method called

                LogMessage(message);

 

                //run the intercepted method

                invocation.Proceed();

 

                //log method return value

                if (invocation.Request.Method.ReturnType != typeof(void))

                {

                    LogMessage(string.Format("Method {0} returned <{1}>", methodName, invocation.ReturnValue));

                }

 

            }

            catch (Exception ex)

            {

                var message = string.Format("Method {0} EXCEPTION occured: {1} ", methodName, ex);

                LogMessage(message);

                throw;

            }

        }

 

        private static void LogMessage(string message)

        {

            Console.WriteLine(string.Format("{0:HH:mm} {1}", DateTime.Now, message));

        }

    }

 

 

Adding the logging interceptor to your NInject Configuration

In your kernel configuration you can add interceptors to your bindings like this :

kernel.Bind<IService>().To<Service>().Intercept().With<LoggingInterceptor>();

Now when getting a IService using Kernel.Get<IService> the logginginterceptor will be interception all method calls :) A working sample console application can be found here: 

SampleLogging.rar (2.86 mb)

SampleLogging.rar (2.86 mb)

 

 

 

Globalizing MVC razor views using cshtml per locale

30. July 2013 21:33 by martijn in .net, globalization, MVC

There are quite a few ways to localize your MVC applications. The best is probably to reference resources (resx) from your cshtml files. For a overview see this complete guide and the post by Hanselman

This can be a bit awkward though if you need a different structure for a different country. Another option is to use a cshtml file per locale. For example use a index.nl.cshtml file for dutch users and index.cshtml for other users. How to do this is the topic of this post. Be aware that this should not be your first choice because you basically copy your HTML making changes later on harder. It can be good to know this trick sometimes... (If you use WebForms viewengine you should use this guide.)


To get this working we need to complete a few steps

  1. Create a localized view
  2. Create a viewengine that prefers localized views and uses the default view if none is found. This makes localization optional and nice to combine with other (resource based) solutions.
  3. Register the ViewEngine in global.asax

Create a localized view

How you structure your views is arbitrary. For this post I post the localized direct next to the normal view. Here I created a Index for the dutch (nl) locale:

Creating the globalized ViewEngine

We subclass the normal RazorViewEngine and only change the part that determines which file is used. We use the CurrentUICulture of the current thread to determine which culture should be used. Then we check to see if there is a view specific for this culture. If no specific view is found the regular view is used.

using System;
using System.IO;
using System.Web.Mvc;
namespace LocalizedViews
{
public sealed class RazorGlobalizationViewEngine : RazorViewEngine
{
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
partialPath = GlobalizeViewPath(controllerContext, partialPath);
return base.CreatePartialView(controllerContext, partialPath);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
viewPath = GlobalizeViewPath(controllerContext, viewPath);
return base.CreateView(controllerContext, viewPath, masterPath);
}
private static string GlobalizeViewPath(ControllerContext controllerContext, string viewPath)
{
var request = controllerContext.HttpContext.Request;
var lang = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;
if (!string.IsNullOrEmpty(lang) && !string.Equals(lang, "en", StringComparison.InvariantCultureIgnoreCase))
{
string localizedViewPath = viewPath.Replace(".cshtml", "." + lang + ".cshtml");
if (File.Exists(request.MapPath(localizedViewPath)))
{
viewPath = localizedViewPath;
}
}
return viewPath;
}
}
}

Registering the ViewEngine in global.asax

We can register the viewengine in the global asax like this:

 protected void Application_Start()

        {

            ViewEngines.Engines.Clear();

            ViewEngines.Engines.Add(new RazorGlobalizationViewEngine());

           //the rest of it..

        }

And that's all there is too it. Happy coding!