Create an XML Sitemap

2 min read

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Security;
using DataAnnotationsExtensions;
using System.Xml.Serialization;
using System.Collections;

namespace Site.Models
{
    [XmlRoot("urlset", Namespace = "http://www.sitemaps.org/schemas/sitemap/0.9")]
    public class Sitemap
    {
        private ArrayList map;
        public Sitemap()
        {
            map = new ArrayList();
        }
        [XmlElement("url")]
        public Location[] Locations
        {
            get
            {
                Location[] items = new Location[map.Count];
                map.CopyTo(items);
                return items;
            }
            set
            {
                if (value == null)
                    return;
                Location[] items = (Location[])value;
                map.Clear();
                foreach (Location item in items)
                    map.Add(item);
            }
        }
        public int Add(Location item)
        {
            return map.Add(item);
        }
    }
    // Items in the shopping list
    public class Location
    {
        public enum eChangeFrequency
        {
            always,
            hourly,
            daily,
            weekly,
            monthly,
            yearly,
            never
        }
        [XmlElement("loc")]
        public string Url { get; set; }
        [XmlElement("changefreq")]
        public eChangeFrequency? ChangeFrequency { get; set; }
        public bool ShouldSerializeChangeFrequency() { return ChangeFrequency.HasValue; }
        [XmlElement("lastmod")]
        public DateTime? LastModified { get; set; }
        public bool ShouldSerializeLastModified() { return LastModified.HasValue; }
        [XmlElement("priority")]
        public double? Priority { get; set; }
        public bool ShouldSerializePriority() { return Priority.HasValue; }
    }
}

Create an RSS feed from your site

< 1 min read

RSS is something quite standard, and as such, is easy to read and create.

We start off with a FeedResult class, which inherits from ActionResult

using System;
using System.ServiceModel.Syndication;
using System.Text;
using System.Web;
using System.Web.Mvc;
using System.Xml;

namespace Data.Controllers
{
    public class FeedResult : ActionResult
    {
        public Encoding ContentEncoding { get; set; }
        public string ContentType { get; set; }
        private readonly SyndicationFeedFormatter feed;

        public SyndicationFeedFormatter Feed{
            get { return feed; }
        }

        public FeedResult(SyndicationFeedFormatter feed) {
            this.feed = feed;
        }

        public override void ExecuteResult(ControllerContext context) {
            if (context == null)
                throw new ArgumentNullException("context");
            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = !string.IsNullOrEmpty(ContentType) ?
                ContentType : "application/rss+xml";
            if (ContentEncoding != null)
                response.ContentEncoding = ContentEncoding;
            if (feed != null)
                using (var xmlWriter = new XmlTextWriter(response.Output)) {
                    xmlWriter.Formatting = Formatting.Indented;
                    feed.WriteTo(xmlWriter);
                }
        }
    }
}

And finally, we create a Controller Method to create the RSS

public ActionResult MyRss()
{
    var postItems = new List();
    using (Repository rep = new Repository())
    {
        var list = rep.GetData();
        if (list != null && list.Count() > 0)
        {
            var itemList = list.Take(20);
            foreach (var item in itemList)
            {
                postItems.Add(
                    new SyndicationItem(
                        item.Title, //a Title for the RSS Item
                        item.Description, //a short description for the Item
                        new Uri("http://example.com/" + item.Link) //a link to this item
                    )
                );
            }
        }
    }
    var feed = new SyndicationFeed("My Site Name", "", new Uri("http://example.com/"), postItems)
    {
        Copyright = new TextSyndicationContent("Copyright " + DateTime.Now.Year + " My Site",
                        TextSyndicationContentKind.Plaintext),
        Language = "en-US"
    };
    return new FeedResult(new Rss20FeedFormatter(feed));
}

Get a string description from an enum

< 1 min read Enums can be very powerful when used appropriately, such as for populating fixed drop-down lists which almost never change

Let’s say you want to save a person’s gender in your database. You could save it as a string, but that’s very wasteful. Ideally you’d save it as tinyint, because it will never have more values, so why waste space and computing time with joins, or other solutions.
Your enum could look like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel;

namespace Data.Enums
{
    public enum Genders : byte
    {
        [DescriptionAttribute("No Answer")]
        NoAnswer = 0,
        [DescriptionAttribute("Male")]
        Male = 1,
        [DescriptionAttribute("Female")]
        Female = 2
    }
}

Log and email errors in MVC 3

3 min read

void Application_Error(object sender, EventArgs e)
{
    ErrorTracking.TrackingInfo info = new ErrorTracking.TrackingInfo();
    info.ErrorPath = "http://" + Request.ServerVariables["HTTP_HOST"] + Request.Path;
    info.RawUrl = Request.RawUrl;
    string strError = "Error in: http://" + Request.ServerVariables["HTTP_HOST"] + Request.Path +
    "nUrl: " + Request.RawUrl + "nn";
    try
    {
        // Get the exception object for the last error message that occured.
        Exception ErrorInfo = Server.GetLastError().GetBaseException();
        if (ErrorInfo != null)
        {
            strError += "Error Message: " + ErrorInfo.Message +
                "nError Source: " + ErrorInfo.Source +
                "nError Target Site: " + ErrorInfo.TargetSite;
            info.ErrorMessage = ErrorInfo.Message;
        }
        strError += "Error Type: " + Server.GetLastError().GetType().ToString();
        info.ErrorType = Server.GetLastError().GetType().ToString();
        if (Server.GetLastError().GetType() == typeof(HttpUnhandledException))
        {
            strError += "Source: " + (Server.GetLastError() as HttpUnhandledException).GetHtmlErrorMessage();
            info.ErrorSource = (Server.GetLastError() as HttpUnhandledException).GetHtmlErrorMessage();
        }
        info.QueryStringData = "";
        strError += "nnQueryString Data:n-----------------n";
        // Gathering QueryString information
        for (int i = 0; i < Context.Request.QueryString.Count; i++)
        {
            strError += Context.Request.QueryString.Keys[i] + ":tt" + Context.Request.QueryString[i] + "n";
            info.QueryStringData += Context.Request.QueryString.Keys[i] + ":tt" + Context.Request.QueryString[i] + "n";
        }
        strError += "nPost Data:n----------n";
        info.PostData = "";
        // Gathering Post Data information
        for (int i = 0; i < Context.Request.Form.Count; i++)
        {
            strError += Context.Request.Form.Keys[i] + ":tt" + Context.Request.Form[i] + "n";
            info.PostData += Context.Request.Form.Keys[i] + ":tt" + Context.Request.Form[i] + "n";
        }
        strError += "nSession Data:n----------n";
        // Gathering Session information
        for (int i = 0; i < Context.Session.Count; i++)
        {
            strError += Context.Session.Keys[i] + ":tt" + Context.Session[i] + "n";
        }
        strError += "n";
        if (User.Identity.IsAuthenticated)
        {
            strError += "User:tt" + User.Identity.Name + "nn";
            info.UserAccountName = User.Identity.Name;
        }
        info.StackTrace = Server.GetLastError().StackTrace;
        strError += "Exception Stack Trace:n----------------------n" + Server.GetLastError().StackTrace +
            "nnServer Variables:n-----------------n";
        // Gathering Server Variables information
        info.ServerVariables = "";
        for (int i = 0; i < Context.Request.ServerVariables.Count; i++)
        {
            strError += Context.Request.ServerVariables.Keys[i] + ":tt" + Context.Request.ServerVariables[i] + "n";
            info.ServerVariables += Context.Request.ServerVariables.Keys[i] + ":tt" + Context.Request.ServerVariables[i] + "n";
        }
        strError += "n";
    }
    catch (Exception s) { strError += s.Message; }
    info.CompleteSource = strError;
    info.SiteKey = Guid.Parse(System.Configuration.ConfigurationManager.AppSettings["ErrorTrackingKey"]);
    info.IsRead = false;
    info.IsResolved = false;
    info.DateLogged = DateTime.Now;
    info.ErrorCause = ErrorTracking.ErrorCauses.Unknown;
    info.UserAccountID = Guid.Empty;
    info.ErrorSource = "";
    info.UserAccountName = "";
    ErrorTracking.ErrorTrackingServiceClient client = new ErrorTracking.ErrorTrackingServiceClient();
    client.SubmitError(info);
    // Send email to developer
    System.Net.Mail.MailMessage m = new System.Net.Mail.MailMessage();
    m.To.Add(System.Configuration.ConfigurationManager.AppSettings["DebugEmail"]);
    m.Subject = "Error occurred on " + Request.ServerVariables["HTTP_HOST"];
    m.IsBodyHtml = false;
    m.Body = strError;
    System.Net.Mail.SmtpClient c = new System.Net.Mail.SmtpClient();
    try
    {
        c.Send(m);
    }
    catch { }
}

C# Active Directory

2 min read

using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;

.Net has a UserPrincipal built-in class, which will allow you quick access to common objects such as the Name and User Principal name

 // create your domain context
 PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
 // define a "query-by-example" principal - here, we search for a UserPrincipal
 // and with the first name (GivenName) of "Bruce"
 UserPrincipal qbeUser = new UserPrincipal(ctx);
 qbeUser.GivenName = "Steve";
 // create your principal searcher passing in the QBE principal
 PrincipalSearcher srch = new PrincipalSearcher(qbeUser);
 // find all matches
 foreach(var found in srch.FindAll())
 {
   // do whatever here - "found" is of type "Principal" - it could be user, group, computer.....
 }

MVC Remote Validator

< 1 min read Let’s take a look at a brand new MVC 3 validator – RemoteAttribute. The Remote validator is very simple to use and yet extremely powerful. Remote is for situations where it is impossible to duplicate server side validation logic on the client, often because the validation involves connecting to a database or calling a service. If all your other validation uses javascript and responds to the user’s input immediately, then it is not a good user experience to require a post back to validate one particular field. This is where the remote validator fits in.
In this example, we are going to add remote validation to the username field to check that it is unique.

[Remote("ValidateUserName", "Account", ErrorMessage = "Username is not available.")]
public string UserName { get; set; }

Remote has three constructors allowing you to specify either a routeName, a controller and action or a controller, action and area. Here we are passing controller and action and additionally overriding the error message

public ActionResult ValidateUserName(string username)
{
    return Json(!username.Equals("duplicate"), JsonRequestBehavior.AllowGet);
}

Dynamic Linq for searching

< 1 min read

 var predicate = PredicateBuilder.True();
 var q = db.Profiles.Where(t => !t.aspnet_Users.aspnet_Membership.IsLockedOut);
 foreach (string keyword in pars)
 {
     string temp = keyword;
     predicate = predicate.And(t => t.FirstName.StartsWith(temp) || t.LastName.StartsWith(temp));
 }

C# Render Razor View as String

< 1 min read The Razor View Engine is very powerful, easy to use, and just overall great for binding data to HTML. But sometimes you need to render HTML for use in Emails, download pages, generate PDF’s, or other purposes, so it would be neat if you could use the Razor View Engine to generate those for you, and just give you the HTML to do with it as you wish. Luckily we have this somewhat built-in, and here’s a wrapper for it.

public string RenderRazorViewToString(string viewName, object model)
{
  ViewData.Model = model;
  using (var sw = new StringWriter())
  {
    var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
    var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
    viewResult.View.Render(viewContext, sw);
    viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

You can now use it as in the following example

var htmlPage = RenderRazorViewToString("~/Views/Home/myview.cshtml", siteModel);

You can of course extend the method above, and pass it your own ViewData, TempData, RouteData, change the View Engine, enable or disable ClientValidation and UnobtrusiveJavasript, and so on.

C# Add and Edit Office Document Custom Properties

< 1 min read Office documents store a lot more information than is obviously visible at first. Microsoft released a library called DSOfile, which is intended for changing properties of Office files if you don’t have Office installed.
First, you need to download the DSOfile from Microsoft. http://support.microsoft.com/kb/224351

Second, you’ll need to reference it in your project

using DSOFile;

Next, you can start looping through the Office predefined properties of each file. Note, some attributes are read-only.

OleDocumentProperties file = new OleDocumentProperties();
file.Open(@"C:myfile.docx", false, dsoFileOpenOptions.dsoOptionDefault);
int charCount = file.SummaryProperties.CharacterCount;
int wordCount = file.SummaryProperties.WordCount;
int pageCount = file.SummaryProperties.PageCount;
file.SummaryProperties.Author = "John Smith";
file.SummaryProperties.Category = "My Category";
file.SummaryProperties.Company = "My Company Inc.";
file.SummaryProperties.Manager = "David Smith";
file.SummaryProperties.Subject = "Sample files";
file.SummaryProperties.Title = "A very sample file";
file.Save();
file.Close(true);

Those might sometimes not be enough, so surely enough you can add your own custom attributes, and use the NTFS File System as your own personal database.

OleDocumentProperties file = new DSOFile.OleDocumentProperties();
file.Open(@"C:myfile.docx", false, DSOFile.dsoFileOpenOptions.dsoOptionDefault);
string key = "My Custom Key"; /* Use any key you want, these will be saved in the file. */
object value = "My Custom Value";
// Check if file has a certain property set
bool hasProperty = false;
foreach (DSOFile.CustomProperty p in file.CustomProperties)
    if (p.Name == key)
        hasProperty = true;
// If it doesn't have the property, add it, otherwise set it.
// This is the only way I found to loop through the properties
if (!hasProperty)
    file.CustomProperties.Add(key, ref value);
else
    foreach (DSOFile.CustomProperty p in file.CustomProperties)
        if (p.Name == key)
            p.set_Value(value);
// Go through existing custom properties.
foreach (DSOFile.CustomProperty p in file.CustomProperties)
{
    Console.WriteLine("{0}:{1}", p.Name, p.get_Value().ToString());
}
file.Save();
file.Close(true);