< 1 min read
public IEnumerable Months { get { return DateTimeFormatInfo .InvariantInfo .MonthNames .Select((monthName, index) => new SelectListItem { Value = (index + 1).ToString(), Text = monthName }); } }
< 1 min read
public IEnumerable Months { get { return DateTimeFormatInfo .InvariantInfo .MonthNames .Select((monthName, index) => new SelectListItem { Value = (index + 1).ToString(), Text = monthName }); } }
2 min read As you might’ve noticed, keeping threads running after a request returns, for processing post operational tasks (such as performing analytics on a file that was uploaded, etc) don’t always complete in a web project.
There are several issues with spawning threads in the context of an ASP.NET project. Phil Haack’s post explains the issues in more detail. The following classes solve the problem of IIS killing threads before they complete.
2 min read Localization in C# is very straightforward. C# comes with Resource files, which are great because they can be easily translated, and C# can switch between them automatically.
First, add a new Resource File to your project. In my case, I called it SiteFields.resx. This will be the default language file, which in this case is English.
Next, we create a Localized Display Name Attribute, so we can leverage our ViewModels properly, instead of relying on text.
public class LocalizedDisplayNameAttribute : DisplayNameAttribute { public LocalizedDisplayNameAttribute(string resourceId) : base(GetMessageFromResource(resourceId)) { } private static string GetMessageFromResource(string resourceId) { CultureInfo culture = null; if (HttpContext.Current.Session["CultureInfo"] != null) culture = (CultureInfo)HttpContext.Current.Session["CultureInfo"]; else culture = CultureInfo.CurrentCulture; return Resources.SiteFields.ResourceManager.GetString(resourceId, culture); } }
< 1 min read I came across this when trying to build a website that takes advantage of sub domains in a MVC project.
You can route subdomains in MVC to a particular controller, and specific actions.
In order to do this, you must make your website listen directly on the IP Address, and point a wildcard A record for all subdomains.
In IIS 7, under Bindings, add a binding for http or https, set the IP to the dedicated IP for the site, and leave the Host name empty.
In your DNS Server (GoDaddy or Windows DNS Server), add the following A records
Host: @ or (same as parent) IP address: (your dedicated IP) Host: * IP address: (your dedicated IP)
NOTE: Not all DNS Servers have wildcard options
This will make your website listen for any subdomains on your site.
Reference the classes attached below, and add the following routes to your project
_routes.Add("BlogRouteProfile", new DomainRoute("{url}.example.com", "", new { controller = "Blog", action = "ViewBlog", url = "" })); _routes.Add("BlogLatestPosts", new DomainRoute("{url}.example.com", "latest-posts", new { controller = "Blog", action = "BlogLatestPosts", url = "" })); _routes.Add("BlogPost1", new DomainRoute("{url}.example.com", "rss", new { controller = "Blog", action = "BlogRss", url = "" })); _routes.Add("BlogPost3", new DomainRoute("{url}.example.com", "pages/{pageName}", new { controller = "Blog", action = "BlogPageView", url = "" }));
In your controller, you can now define Actions, just as you normally would for a regular route.
public class BlogController : Controller { public ActionResult BlogPageView(string url, string pageName) { return View(); } }
2 min read
using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D;
public class PhotoRouteHandler : IRouteHandler { public IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.Response.Clear(); //Cache the photo in the browser to avoid unnecessary requests. HttpCachePolicyBase cache = requestContext.HttpContext.Response.Cache; TimeSpan cacheDuration = TimeSpan.FromSeconds(86400); cache.SetCacheability(HttpCacheability.Public); cache.SetExpires(DateTime.Now.Add(cacheDuration)); cache.SetMaxAge(cacheDuration); cache.AppendCacheExtension("must-revalidate, proxy-revalidate"); //Get the size and url of the photo string photoUrl = requestContext.RouteData.Values["photoUrl"].ToString(); string size = requestContext.RouteData.Values["size"].ToString(); //Set the content type of the response requestContext.HttpContext.Response.ContentType = GetContentType(photoUrl); Image img = null; Image source; bool resizedFile = false; //Check if the photo already exists resized on your HDD if (File.Exists(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl))) { img = Image.FromFile(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl)); resizedFile = true; } else { try { //Try to get the photo from the HDD source = Image.FromFile(Path.Combine(@"C:MySiteContentPhotos", photoUrl)); } catch { //If photo doesn't exist on your HDD, send back the default image placeholder source = Image.FromFile(Path.Combine(@"C:MySiteContentPhotos", "default.jpg")); resizedFile = true; //Used later so we don't store the placeholder } // Resize the image to completely fit into the size of the rectangle if (size == "thumb") img = Thumbnailer.FillImage(Thumbnailer.ResizeImage(source, new Size(119, 88)), new Size(119, 88), Thumbnailer.Anchor.Center); // Resize and crop the image to completely fill the rectangle else if (size == "small") img = Thumbnailer.ResizeCrop(source, new Size(284, 205)); // Resize the image to have a width of 516px else if (size == "large") img = Thumbnailer.ResizeImage(source, Thumbnailer.GetNewSize(source.Size, new Size(516, 516), Thumbnailer.ResizeMode.FixedWidth)); // Default rezise for all images where size wasn't accounted for else img = Thumbnailer.ResizeImage(source, Thumbnailer.GetNewSize(source.Size, new Size(400, 300), Thumbnailer.ResizeMode.FixedWidth)); } if (img != null) { if (GetContentType(photoUrl) == "image/png") { MemoryStream memImg = new MemoryStream(); EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 1000L); ImageCodecInfo pngCodec = Thumbnailer.getEncoderInfo("image/png"); EncoderParameters encoderParams = new EncoderParameters(1); encoderParams.Param[0] = qualityParam; if (!resizedFile) { //This is the first time this photo has been viewed at this size, so we'll save //it in a folder named after the size, so we don't have to resize it again later if (!Directory.Exists(Path.Combine(@"C:MySiteContentPhotos", size))) Directory.CreateDirectory(Path.Combine(@"C:MySiteContentPhotos", size)); img.Save(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl), pngCodec, encoderParams); } img.Save(memImg, pngCodec, encoderParams); memImg.WriteTo(requestContext.HttpContext.Response.OutputStream); img.Dispose(); } else { MemoryStream memImg = new MemoryStream(); EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L); ImageCodecInfo jpegCodec = Thumbnailer.getEncoderInfo("image/jpeg"); EncoderParameters encoderParams = new EncoderParameters(1); encoderParams.Param[0] = qualityParam; if (!resizedFile) { if (!Directory.Exists(Path.Combine(@"C:MySiteContent", "Photos", size))) Directory.CreateDirectory(Path.Combine(@"C:MySiteContentPhotos", size)); img.Save(Path.Combine(@"C:MySiteContent", "Photos", size, photoUrl), jpegCodec, encoderParams); } img.Save(memImg, jpegCodec, encoderParams); memImg.WriteTo(requestContext.HttpContext.Response.OutputStream); img.Dispose(); } } requestContext.HttpContext.Response.End(); return null; } private static string GetContentType(String path) { switch (Path.GetExtension(path)) { case ".bmp": return "image/bmp"; case ".gif": return "image/gif"; case ".jpg": return "image/jpeg"; case ".png": return "image/png"; default: break; } return ""; } }
< 1 min read The “OnActionExecuting” method is fired before every Action in a MVC controller. You can use this method to set and retrieve variables that are useful throughout your session, such as the person’s name, their profile photo, etc.
The following is an example implementation of this method
public class HomeController : Controller { protected override void OnActionExecuting(ActionExecutingContext ctx) { base.OnActionExecuting(ctx); using (Repository rep = new Repository()) { if (Request.IsAuthenticated) { var profile = rep.GetProfileByID((Guid)Membership.GetUser().ProviderUserKey); ViewBag.Name = profile.DisplayName; } } } public ActionResult Index() { //your code return View(); } //rest of your methods }
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; } } }
< 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)); }
< 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 } }
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 { } }