Follow me on Twitter

First time here?

Check out the Archive, and Subscribe to the RSS feed.

IISAPP equivalent in IIS 7 and beyond

This post was written on March 8, 2010 23:53 by MartinHN

If there’s one change I hate about IIS 7 and beyond, it is the lack of the very useful IISAPP script that was present on IIS 6 installations. Run it from a command prompt, and you will see a list of all running worker processes, the process id and the application pool name the process is serving. Very useful if you need to shut down a single site.

As I mentioned, that script was removed in IIS 7 and beyond. I find myself constantly running IISAPP without any luck several time a week, and I’ve decided that this is a habit that I cannot leave behind.

So, to solve the problem I’ve created this small .bat file and copied it to the C:\Windows\System32\inetsrv folder. The content of the iisapp.bat file is just a single line, that does exactly the same as the old IISAPP did – just using the new APPCMD in IIS 7 instead:

appcmd list wp


Now I can call IISAPP and see a list of running applications:

image 
And now my day got a whole lot better. To wrap it up, I’ll put the path to the inetsrv folder in my PATH environment variable so that I can call IISAPP form anywhere.

Tags: , ,
Categories: IIS7
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Unit test for verifying references from DataAnnotation validation to the ErrorMessageResourceName value

This post was written on March 4, 2010 17:52 by MartinHN

I love the new model validation features in System.ComponentModel.DataAnnotations. One thing I don’t like though, is that the ErrorMessageResourceName is loosely typed. The ErrorMessageResourceType, however, is a System.Type which will be strongly typed by assigning its value using the typeof(Namespace.ResourceSetType) method.

Since there’s no build-breaking reference between a resource file and the value of the ErrorMessageResourceName on all classes where you use it, I thought it would be cool to have a unit test that verifies the existence of all referenced resource keys.

Remember to add a reference to System.ComponentModel.DataAnnotations.

Code

 

/// <summary>
/// Verifies that all properties that are decorated with validation data-annotations, refers to 
/// an existing resource. This will make sure, that missing resources are not referenced.
/// </summary>
[TestMethod]
public void All_Properties_With_Validation_Annotations_Must_Refer_To_Existing_Resource()
{
    Assembly assembly = Assembly.Load(new AssemblyName("MyApp.Model.Namespace"));
    var types = assembly.GetTypes().Where<Type>(t => t.IsClass && !t.IsAbstract);

    foreach (var type in types)
    {
        var properties = type.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            var attributes = property.GetCustomAttributes(true);

            foreach (var item in attributes)
            {
                if (item is ValidationAttribute)
                {
                    ValidationAttribute val = item as ValidationAttribute;

                    Assert.IsNotNull(val);

                    if (val.ErrorMessageResourceType != null)
                    {
                        Assert.AreNotEqual(String.Empty, val.ErrorMessageResourceName, 
                            String.Format(@"Validation Error Resource specified on property: 
                        {0}.{1} is empty!", type.ToString(), property.Name));

                        try
                        {
                            ResourceManager rm = new ResourceManager(val.ErrorMessageResourceType);
                            string resourceValue = rm.GetString(val.ErrorMessageResourceName);
                            Assert.IsFalse(String.IsNullOrEmpty(resourceValue), 
                                String.Format(@"The value of the Validation Error Resource specified on property: 
                            {0}.{1} is empty!", type.ToString(), property.Name));
                        }
                        catch (MissingManifestResourceException)
                        {
                            Assert.Fail(String.Format(@"Validation Error Resource specified on property: 
                            {0}.{1} could not be found!", type.ToString(), property.Name));
                        }
                    }
                }
            }
        }
    }
}

Multiple SSL certificates on IIS using host headers

This post was written on March 4, 2010 00:35 by MartinHN

In IIS SSL sites have seemed to be limited to only one site per network interface, since you (from IIS Manager) cannot specify a host header binding on the HTTPS protocol.

It turns out, that it is only a limitation in the UI. So to have e.g. two sites with their own dedicated SSL certificate we need to add a host header binding on port 443 from either appcmd, managed code or by editing the applicationHosts.config file.

I like managed code the most, so I’ve written a small method in C# that does the trick. You need to have two SSL certificates named www.ssl1.com and www.ssl2.com installed on the machine. I just created a self signed certificate for both of them using the IIS Manager.

using System.Security.Cryptography.X509Certificates;
using Microsoft.Web.Administration;

namespace IisSsl
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServerManager _serverManager = new ServerManager())
            {
                string siteName = "SSL2";
                string certName = "www.ssl2.com";

                X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
                store.Open(OpenFlags.ReadOnly);

                X509Certificate2 certificate = store.Certificates[0];
                
                Site site = _serverManager.Sites[siteName];

                if (site != null)
                {
                    site.Bindings.Add("*:443:" + certName, 
                        certificate.GetCertHash(), store.Name);
                }
                store.Close();

                _serverManager.CommitChanges();
            }
        }
    }
}

 

Remember to add a reference to C:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll in order to use the ServerManager class.

Tags: ,
Categories: IIS7 | C#
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

ASP.NET MVC View Page Editor in Visual Studio 2010 Beta 2 won’t recognize HTML tags

This post was written on October 21, 2009 13:24 by MartinHN

I love the new IntelliSense dialog in Visual Studio 2010 Beta 2, that ScottGu has blogged about. But when editing an ASP.NET MVC View Page in Visual Studio 2010 Beta 2, you end up fighting the IntelliSense. That is because IntelliSense and the HTML Editor doesn’t recognize *any* HTML tags.

image

Trying to add a simple paragraph tag in HTML suggests a panel (code snippet). When you finish the P tag, by typing >, the result is this:

image

Pretty annoying to fight with IntelliSense when you want to code! I thought you might be able to fix this, by deleting all the new ASP.NET specific code snippets in the “C:\Program Files\Microsoft Visual Studio 10.0\Web\Snippets\HTML\1033\ASP.NET” folder.

This actually works. Now you can actually see the ASP.NET MVC code snippets, that was hidden in the masses of the ASP.NET ones.

image

But it still has all the ASP.NET Server Controls listed. I thought I could get rid of these by removing a namespace reference to System.Web in the Pages section of Web.config. But that is not present. So I don’t know how to fix that.

Search Twitter from C# using LINQ to XML

This post was written on March 16, 2009 21:28 by MartinHN

In some applications, it could be cool to have a feature that enabled the user to quickly get a glimpse of what people are saying on Twitter about the user or their product, service, company etc.

For instance, a service like GetSatisfaction.com has a feature just like that. They call it Overheard, and this is what it looks like:

overheard

There’s nothing like Twitter to give you feedback. I think MediaTemple felt the effect of unhappy customers on Twitter when their servers broke down, and stayed there for more than two days!

Anyway. I wanted to search from C#, and get back a DataTable. Here’s how it’s done:

    /// <summary>
    /// Searches Twitter for the specified query.
    /// </summary>
    /// <param name="query">The query.</param>
    /// <returns>Returns the search results as a DataTable</returns>
    public DataTable Search(string query)
    {
      DataTable dt = new DataTable();
      dt.Columns.Add("text");
      dt.Columns.Add("html");
      dt.Columns.Add("pubdate");
      dt.Columns.Add("id");
      dt.Columns.Add("link");
      dt.Columns.Add("authorname");
      dt.Columns.Add("authorlink");

      XDocument tweetResults = XDocument.Load(String.Format(
      "http://search.twitter.com/search.atom?q={0}", HttpUtility.UrlEncode(query)));
      XNamespace atomNS = "http://www.w3.org/2005/Atom";
      var q = from tweet in tweetResults.Descendants(atomNS + "entry")
              select new
              {
                Text = (string)tweet.Element(atomNS + "title"),
                Html = (string)tweet.Element(atomNS + "content"),
                DatePublished = DateTime.Parse((string)tweet.Element(atomNS + "published")),
                Id = (string)tweet.Element(atomNS + "id"),
                Link = (string)tweet.Elements(atomNS + "link")
                .Where(link => (string)link.Attribute("rel") == "alternate")
                .Select(link => (string)link.Attribute("href"))
                .First(),
                Author = (from author in tweet.Descendants(atomNS + "author")
                          select new
                          {
                            Name = (string)author.Element(atomNS + "name"),
                            Uri = (string)author.Element(atomNS + "uri"),
                          }).First()
              };
      
      foreach (var item in q)
      {
        dt.Rows.Add(item.Text, item.Html, item.DatePublished, item.Id, item.Link, 
                    item.Author.Name, item.Author.Uri);
      }

      return dt;
    }

Tags: , ,
Categories: C#
Actions: E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed

Migrate web.config to support the IIS 7 Integrated Pipeline

This post was written on March 15, 2009 22:13 by martinhn

Whenever you deploy a website to IIS 7 that is not compliant with the IIS 7 integrated pipeline, you will get an error like this one:

iis7-integrated-pipeline-error

Not the great error message you get. It actually gives you the solution right away: Migrate Web.config to support the integrated pipeline. To do that, start a command prompt, and execute:

%SystemRoot%\system32\inetsrv\appcmd migrate config "test/"

After doing this, our Web.config is changed to support the IIS 7 integrated pipeline and we can see the website.

Automatically translate Global and Local Resource (resx) files

This post was written on March 13, 2009 22:31 by MartinHN

Yesterday, I blogged about how you can use Google Translate to translate a string in C#. To make it more useful than just a simple translator, and because I need to translate some Global Resource files for an E-commerce website that I’m working on, I wanted to create a small Windows Application in C# that could read a Global Resource file (.resx) and translate it into a selected language using the method for translating a word in C# that i blogged about yesterday.

image

This is how it looks so far. You simply select the resource file you want to translate. Select the current language of the resource file in the middle box, and select the language you want to translate it to in the last box. Click Translate at it should work. The new resource file will be saved in the same location as the application itself.

Translate text in C#, using Google Translate

This post was written on March 12, 2009 00:14 by martinhn

Sometimes, it would be great to be able to translate a text from e.g. English to Danish directly from C#. This could be useful when you want to translate a Resource file into another language.

Google Translate is awesome. There’s also Windows Live Translator, but Microsoft are far behind Google (also) in this game.

Code:

using System;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace Utilities
{
  public static class Translator
  {
    /// <summary>
    /// Translates the text.
    /// </summary>
    /// <param name="input">The input.</param>
    /// <param name="languagePair">The language pair.</param>
    /// <returns></returns>
    public static string TranslateText(string input, string languagePair)
    {
      return TranslateText(input, languagePair, System.Text.Encoding.UTF7);
    }

    /// <summary>
    /// Translate Text using Google Translate
    /// </summary>
    /// <param name="input">The string you want translated</param>
    /// <param name="languagePair">2 letter Language Pair, delimited by "|". 
    /// e.g. "en|da" language pair means to translate from English to Danish</param>
    /// <param name="encoding">The encoding.</param>
    /// <returns>Translated to String</returns>
    public static string TranslateText(string input, string languagePair, Encoding encoding)
    {
      string url = String.Format("http://www.google.com/translate_t?hl=en&ie=UTF8&text={0}&langpair={1}", input, languagePair);

      string result = String.Empty;

      using (WebClient webClient = new WebClient())
      {
        webClient.Encoding = encoding;
        result = webClient.DownloadString(url);
      }

      Match m = Regex.Match(result, "(?<=<div id=result_box dir=\"ltr\">)(.*?)(?=</div>)");

      if (m.Success)
        result = m.Value;

      return result;
    }
  }
}

The translated string is fetched by the RegEx close to the bottom. This could of course change, and you have to keep it up to date.

ASP.NET Search Engine Optimization

This post was written on March 11, 2009 17:46 by martinhn

I made a few E-commerce websites a few years back when I was self-employed. Ranking well in the search engines is very important for E-commerce websites in order to get relevant visitors, and if your site is designed well for converting, visitors into sales, you will make money. That’s the way it goes.

A lot of naive CEO’s and alike, think that you absolutely have to hire expensive SEO consultants in order to rank well. That is *not* true. Instead, why don’t you just spent your time and money on making original, relevant and great content? That’s a true winner.

Though, there’s still a few technical details you have to get right.

Make sure to set a unique page title on all your pages. Use the same text as a <h1> tag on the page.

Don’t screw up your URLs. You will get punished having the same content on those URLs: www.example.com/producs/computers?sortorder=price&page=2 and www.example.com/producs/computers?page=2&sortorder=price. This is called duplicate content, and search engines doesn’t like that. You can use the new canonical tag for telling search engines which one is original.

Make internal links absolute. Yes. You shouldn’t do this: <a href=”/page1.htm”>Page 1</a>. Do this instead: <a href=”http://www.example.com/page1.htm”>Page 1</a>.

301 permanent redirect example.com to www.example.com or vice versa. Allowing visitors to access your page on both URLs, will also be treated as duplicate content.

If you’re moving your website to a new platform, server, technology and your URLs will change. Make sure not to return 404 on the old URLs. You have to 301 permanent redirect the old URLs to the new ones. Otherwise you will lose all your current search engine carma.

I use those two methods to set page information, and 301 redirect:

  private void SetMetaInformation()
  {
    this.Title = PageTitle;

    HtmlMeta metaKeywords = new HtmlMeta();
    metaKeywords.Name = "keywords";
    metaKeywords.Content = this.MetaKeywords;
    this.Header.Controls.Add(metaKeywords);

    HtmlMeta metaDescription = new HtmlMeta();
    metaDescription.Name = "description";
    metaDescription.Content = this.MetaDescription;
    this.Header.Controls.Add(metaDescription);

    HtmlMeta metaRobots = new HtmlMeta();
    metaRobots.Name = "robots";
    metaRobots.Content = this.MetaRobots;
    this.Header.Controls.Add(metaRobots);
  }

  public void PermanentRedirect(string newUrl)
  {
    Response.Status = "301 Moved Permanently";
    Response.StatusCode = 301;
    Response.AddHeader("Location", newUrl);
  }
 
 

You also want to take a look at the Google SiteMap.

Create a generic handler in ASP.NET and call it sitemap.ashx. Generate and XML string like this:

 
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
   <url>
      <loc>http://www.example.com/</loc>
      <lastmod>2005-01-01</lastmod>
      <changefreq>monthly</changefreq>
      <priority>0.8</priority>
   </url>
</urlset> 

 

Take a further look at the importance of sitemaps, if you want to know why you should use one.

Tags: , ,
Categories: ASP.NET
Actions: E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

C# TwitPic API client

This post was written on March 10, 2009 22:51 by martinhn

I’ve spent some time lately, playing around with the Twitter API. And along with that belongs the TwitPic’s API. I’m using Twitter a lot, to stay in touch with tech news, other developers and just for fun. But it’s getting more and more used for a lot of different things, and I needed it to integrate with an E-commerce platform I’m developing.

The code for post a picture to TwitPic looks like this:

    /// <summary>
    /// URL for the TwitPic API's upload method
    /// </summary>
    private const string TWITPIC_UPLADO_API_URL = "http://twitpic.com/api/upload";

    /// <summary>
    /// URL for the TwitPic API's upload and post method
    /// </summary>
    private const string TWITPIC_UPLOAD_AND_POST_API_URL = "http://twitpic.com/api/uploadAndPost";

    /// <summary>
    /// Uploads the photo and sends a new Tweet
    /// </summary>
    /// <param name="binaryImageData">The binary image data.</param>
    /// <param name="tweetMessage">The tweet message.</param>
    /// <param name="filename">The filename.</param>
    /// <returns>Return true, if the operation was succeded.</returns>
    public bool UploadPhoto(byte[] binaryImageData, string tweetMessage, string filename)
    {
      // Documentation: http://www.twitpic.com/api.do
      string boundary = Guid.NewGuid().ToString();
      string requestUrl = String.IsNullOrEmpty(tweetMessage) ? TWITPIC_UPLADO_API_URL : TWITPIC_UPLOAD_AND_POST_API_URL;
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
      string encoding = "iso-8859-1";

      request.PreAuthenticate = true;
      request.AllowWriteStreamBuffering = true;
      request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
      request.Method = "POST";

      string header = string.Format("--{0}", boundary);
      string footer = string.Format("--{0}--", boundary);

      StringBuilder contents = new StringBuilder();
      contents.AppendLine(header);

      string fileContentType = GetImageContentType(filename);
      string fileHeader = String.Format("Content-Disposition: file; name=\"{0}\"; filename=\"{1}\"", "media", filename);
      string fileData = Encoding.GetEncoding(encoding).GetString(binaryImageData);

      contents.AppendLine(fileHeader);
      contents.AppendLine(String.Format("Content-Type: {0}", fileContentType));
      contents.AppendLine();
      contents.AppendLine(fileData);

      contents.AppendLine(header);
      contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "username"));
      contents.AppendLine();
      contents.AppendLine(this.Username);

      contents.AppendLine(header);
      contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "password"));
      contents.AppendLine();
      contents.AppendLine(this.Password.ToInsecureString());

      if (!String.IsNullOrEmpty(tweetMessage))
      {
        contents.AppendLine(header);
        contents.AppendLine(String.Format("Content-Disposition: form-data; name=\"{0}\"", "message"));
        contents.AppendLine();
        contents.AppendLine(tweetMessage);
      }

      contents.AppendLine(footer);

      byte[] bytes = Encoding.GetEncoding(encoding).GetBytes(contents.ToString());
      request.ContentLength = bytes.Length;

      using (Stream requestStream = request.GetRequestStream())
      {
        requestStream.Write(bytes, 0, bytes.Length);

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
          using (StreamReader reader = new StreamReader(response.GetResponseStream()))
          {
            string result = reader.ReadToEnd();

            XDocument doc = XDocument.Parse(result);

            XElement rsp = doc.Element("rsp");
            string status = rsp.Attribute(XName.Get("status")) != null ? rsp.Attribute(XName.Get("status")).Value : rsp.Attribute(XName.Get("stat")).Value;

            return status.ToUpperInvariant().Equals("OK");
          }
        }
      }
    }
Tags: , ,
Categories: C#
Actions: E-mail | Permalink | Comments (9) | Comment RSSRSS comment feed

Powered by BlogEngine.NET 1.6.0.0

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in  anyway.

© Copyright 2010