2014-09-17

PowerShell Profile with Permanent Aliases

Powershell

If you're a PowerShell-user who manually runs scripts or binds an alias every time you open PowerShell, then there is a file you really should know about. It's the PowerShell profile-file (or actually, the six profile-files).

I use the profile-file for Current User in the console located here:

%UserProfile%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1

When you've ensured that this file is created you can enter PowerShell-scripts that will run every time you open your PowerShell-console. Ensure that your execution policy is configured to support this:

Set-ExecutionPolicy -ExecutionPolicy Unrestricted

For example you can create a PowerShell-alias for the git-command to work with just using g instead:

set-alias g git

Now I can just type g status and save many, many seconds and key-strokes during a long week of Git-usage.

2014-03-11

Render .ascx-Files in ASP.NET MVC Using Only RazorViewEngine

ASP.NET Band-Aid

If you're stuck in an environment where you're migrating from ASP.NET MVC to ASP.NET WebForms it's good to know that you can actually render your existing WebForms-Controls in you MVC-views. This might sound like a crazy thing to do (and it is in the long run!) but it might be useful if you're stuck between sprints and have perfectly working WebForms-Controls (.ascx-files) that you don't have time to migrate right now. All you have to do is use the HtmlHelper's helper-method .RenderPartial(string partialViewName) and pass it the path to the WebForms-Control.

// Write the content of a control inside a view:
Html.RenderPartial("~/Controls/ControlVirtualPath.ascx");

// Or to get the content of a control as a MvcHtmlString, for further manipulation:
Html.Partial("~/Controls/CustomControl.ascx")

It's important that your controls inherits from System.Web.Mvc.ViewUserControl and NOT the old System.Web.UI.UserControl.

One performance-tip that is often mentioned around ASP.NET MVC is to deactivate the WebForms-View Engine for MVC Razor-views (which actually turns out to maybe not make such a big difference after all). This will not prevent .aspx, .ascx and other WebForms-files from working.

But you still want your .ascx-files to work inline in your MVC Razor-views. This can be achieved by implementing your own class that inherits RazorViewEngine, which only uses the WebFormViewEngine when actually needed.

Global.asax (or other config-class)

// Remove WebFormViewEngine (and RazorViewEngine)
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomRazorViewEngine());

CustomRazorViewEngine : System.Web.Mvc.RazorViewEngine

private static readonly WebFormViewEngine WebFormsEngine = new WebFormViewEngine();

public override ViewEngineResult FindPartialView(
    ControllerContext context, string name, bool useCache)
{
    if (name.EndsWith(".ascx"))
    {
        return WebFormsEngine.FindPartialView(context, name, useCache);
    }

    return base.FindPartialView(context, name, useCache);
}

If you need the actual class of the control to do some further analysis/manipulation, you can do the following anywhere in your code:

var viewPage = new ViewPage();
var control = viewPage.LoadControl("~/Controls/ControlVirtualPath.ascx") as ControlType;

2014-03-02

Serialize HtmlString & MvcHtmlString in JSON.NET

JSON

The HtmlString-class (and MvcHtmlString) that is and has been used in the ASP.NET-platform, including WebPages, since the introduction of ASP.NET MVC is basically just a wrapped string, that doesn't gets automatically HTML-encoded when used in Razor-views. Despite this fact, if you want to serialize or deserialize this object in JSON.NET it will come back as null.

To be able to serialize an object containing a property of a type inheriting from IHtmlString, like HtmlString and MvcHtmlString, to then, for instance, cache the serialized object, you need to implement your own Newtonsoft.Json.JsonConverter that handles the serialization and deserialization.

HtmlStringConverter : Newtonsoft.Json.JsonConverter

public override bool CanConvert(Type objectType)
{
    return typeof(IHtmlString).IsAssignableFrom(objectType);
}

public override object ReadJson(
    JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var value = reader.Value as string;
    // Specifically MvcHtmlString
    if (objectType == typeof(MvcHtmlString))
    {
        return new MvcHtmlString(value);
    }
    // Generally HtmlString
    if (objectType == typeof(HtmlString))
    {
        return new HtmlString(value);
    }

    // Fallback for other (future?) implementations of IHtmlString
    return Activator.CreateInstance(objectType, value);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    var htmlString = value as HtmlString;
    if (htmlString == null)
    {
        return;
    }

    writer.WriteValue(htmlString.ToString());
}

You then have to register this Converter in your JsonSerializerSettings like this:

CurrentConverter.Converters.Add(new HtmlStringConverter());

2014-02-28

Rewrite Old URLs with Regex into RouteValueDictionary

Rewrite

Have you ever needed to rewrite/redirect old URLs that have very similar pattern as your new, modern URLs, but want to do it with simple, maintainable code?

In the following URL you very specifically can see an ID-value and a potential Category-value.

http://test.com/products/details.aspx?id=123&category=tea-cups

So you probably want to use Regex and point out named groups in above URL.

^(?:.*)\/?products\/details\.aspx\?id=(?<id>[\d]*)(&category=(?<category>[^&]*))?

Then you want to get those named values into a RouteValueDictionary, with above named Keys, like <id> and <category> with the Regex-matched Values in the URL. You can then, for example, send it to a UrlHelper. This is what the following method does:

public static RouteValueDictionary GetRegexRouteValues(string url, string urlPattern)
{
    if (url == null)
    {
        throw new ArgumentNullException("url");
    }
    if (urlPattern == null)
    {
        throw new ArgumentNullException("urlPattern");
    }

    var regex = new Regex(urlPattern);
    var match = regex.Match(url);
    if (!match.Success)
    {
        return null;
    }

    var namedGroupNames = regex.GetGroupNames().Where(x => x != null && !Regex.IsMatch(x, @"^[0-9]+$"));
    var groups = (from groupName in namedGroupNames
                  let groupItem = match.Groups[groupName]
                  where groupItem != null
                  select new KeyValuePair<string, string>(groupName, groupItem.Value)).ToList();

    var routeValues = new RouteValueDictionary();
    groups.ForEach(x => routeValues.Add(x.Key, x.Value));

    return routeValues;
}

Now you can write code that is more easy to read and maintain to redirect specific URLs:

private static void RedirectProductDetails(string requestUrl) {
    string urlRegex = @"^(?:.*)\/?products\/details\.aspx\?id=(?<id>[\d]*)(&category=(?<category>[^&]*))?";
    var routeValues = GetRegexRouteValues(requestUrl, urlRegex);

    routeValues["controller"] = "Products";
    routeValues["action"] = "Details";
    return this.Url.RouteUrl(routeValues);
}

2013-03-25

ViewSource - View Source in Mobile Browsers

ViewSource Screenshot

Here's another small app that I created to play around with some code, but mostly because I felt I had a need for it.

ViewSource is an app for viewing the HTML-source of any website from your web-browser. Which enables you to view source from mobile browsers.

Just enter any URL and view the HTML-source. You also get a list of CSS-files and JavaScript-files, which you can view the source of, instantly in your browser.

You can quickly reach the app through bit.ly/vsource.

Fork on GitHub

As always, the source is available on GitHub for forking.

2013-03-19

IIS URL Rewrite-Rules Skipping Files-types

IIS Welcome

If you need to put in a rule for the IIS URL Rewrite Module, but need the rule to skip some file-endings and/or targets that are directories or actual files on disk, this is the post for you.

Following some SEO best-practices that tells us to use trailing slashes on our URLs I used the IIS Manager and added the IIS URL Rewrite-module's built-in rule "Append or remove the trailing slash symbol", which creates the following rule:

 <rule name="Add trailing slash" stopProcessing="true">
  <match url="(.*[^/])$" />
  <conditions>
    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
  </conditions>
  <action type="Redirect" redirectType="Permanent" url="{R:1}/" />
</rule>

This rule takes into account and doesn't apply the rule to files and directories that exists on disk. But there is a big problem with this generic rule.

If you are dynamically serving up files with extensions, then an URL like:

http://website.com/about.html

will become:

http://website.com/about.html/

Adding conditions for specific file-endings

To solve this you can add conditions for certain file-endings, like .html and .aspx:

<conditions>
  <!-- ... -->
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.html$" negate="true" />
  <add input="{REQUEST_FILENAME}" pattern="(.*?)\.aspx$" negate="true" />
</conditions>

Since the rules above already don't apply for files physically on disk, you don't need to add file-endings like .css, .png or .js.

Update: Match ANY file-ending

If you want to match just any file-ending at all, you use the following pattern:

<conditions>
  <!-- ... -->
  <add input="{URL}" pattern=".*/[^.]*\.[\d\w]+$" negate="true" />
</conditions>

2013-02-20

ASP.NET: Transform Web.config with Debug/Release on Build

Web.config Transformation

Did you ever wish you could run your web application with the Web.config being transformed according to the current Solution Configuration for Debug or Release directly from Visual Studio? Well, with some pre-build-magic we can do this.

Files in project

Create a file named Web.Base.config, besides the existing Web.Debug.config and Web.Release.config. This file will be the equivalent to your old Web.config, as it will be the base for the tranformation. You will end up with these files:

  • Web.config
  • Web.Base.config
  • Web.Debug.config
  • Web.Release.config

Web.config

Add the following configuration to the bottom of your .csproj-file, just before the closing </Project>-tag:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
    <TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>

UPDATE: From a reminder in the comments I realized that I also have a problem with Visual Studio transforming the XML twice, when Publishing a project. The solution to this is to add a Condition to the Target-tag like this:

<Target Name="BeforeBuild" Condition="'$(PublishProfileName)' == '' And '$(WebPublishProfileFile)' == ''">

You can now build, run your project or publish it all depending on what Solution Configuration you have selected. Debug or Release. Just press your CTRL+SHIFT+B and see the Web.config-file be transformed.

Version control

I recommend that you leave Web.config out of your Version Control. This solution for transforming the Web.config on the fly would mean that this specific file would constantly be modified and if one person is working with Debug and another person is working with Release the Web.config would probably get big changes constantly.

Testing-tool

The people over at elmah.io has created the Web.config Transformation Tester, where you can try out what the result will be of combining a Web.config-file with a transformation.

The tool can even show you what the diff from the original file is when the transformation is applied.

2013-01-23

MVC: Get Current Action and Controller in View

Have you ever needed to know what Action and/or Controller that is currently used in your View? This might be most helpful in an Layout-file, used by another View.

string currentAction =
    ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
string currentController =
    ViewContext.Controller.ValueProvider.GetValue("controller").RawValue).ToString();

Then you can do customization code like this in your _Layout.cshtml-file.

bool isIndexPage = currentAction.Equals("index", StringComparison.InvariantCultureIgnoreCase)
    && currentController.Equals("blog", StringComparison.InvariantCultureIgnoreCase);

Disclaimer: Of course this breaks the fundamental rules of separation of concerns in MVC, between the View and the Controller, but sometimes you just don't want, or can, pass around sufficient data between the View and the Controller.