Deploying an Azure Project using TFS 2010#

For those few of you left that read my blog, you are probably wondering if I just quit writing.  Well I have been super busy creating Facebook apps that run in Azure.  And these kind of marketing apps that we are doing have marketing deadlines, which are hard to budge.  So that means many late nights and not much time left to write.  I am writing this on the plane now on the way to MIX 2010 where I am speaking on this topic.  I am very excited to be able to speak at MIX.  I am also tired since i am leaving SXSW.  Awesome conference by the way!  Anyway on with the post. :)

So, one of the biggest pains in any development is deployment.  And when it comes to Azure, it is easy to deploy, but still is a very manual process.  Also you need to deploy from your local Visual Studio which can be very problematic.  For instance, lets say you publish your package locally, deploy to staging only to find out that another developer had just checked in a fix and you forgot to get latest before you deployed.  Well since it can take sometimes 15 minutes to deploy to staging because of firing up multiple instances, this can become very painful to have to deploy again right after you just did because of one simple css change or any other change.

So after going through this pain more than once, actually more like 30+ times, I got off of my butt and figured out how to deploy to azure from TFS 2010.  This was a lot of work actually to get to work.  First thing you have to be able to do is build the cloud project on the server. After trying to change the registry, etc to get the Azure targets file to work, I decided just to install visual studio 2010 on the server along with the Azure SDK.  This is the only way I knew that it would actually build. 

So compiling the solution on the server is the first step.  The second step is to actually package the solution so that is can be deployed to Azure.  You have to do this by command line using cspack.  This was also a little tricky as I had to figure out where the path was for the web and worker roles for the cspack to know what to package.  Basically there is a folder called ProjectName.csx where your compiled app is placed when it is built.  Here is the entire package script that is invoked in the TfsBuild.proj file. 

<PackageCommand> 
"C:\Program Files\Windows Azure SDK\v1.1\bin\cspack" "C:\Builds\1\AzureFacebook\AzureFacebookAzureDeploy\Binaries\Release\AzureFacebook.Cloud.csx\ServiceDefinition.csdef"

/role:AzureFacebook.Web;"C:\Builds\1\AzureFacebook\AzureFacebookAzureDeploy\Binaries\Release\AzureFacebook.Cloud.csx\roles\AzureFacebook.Web\approot";

AzureFacebook.Web.dll /role:AzureFacebook.WorkerRole;"C:\Builds\1\AzureFacebook\AzureFacebookAzureDeploy\Binaries\Release\AzureFacebook.Cloud.csx\roles\AzureFacebook.WorkerRole\approot";

AzureFacebook.WorkerRole.dll /out:"C:\Builds\1\AzureFacebook\AzureFacebookAzureDeploy\Binaries\Release\AzureFacebook.cspkg"
</PackageCommand>

After it is packed, you need to then deploy it. I took the sample script from here on the azure cmdlets project and then called out to it from the TfsBuild.proj script like this:

<DeployCommand>
C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe -command C:\Builds\1\AzureFacebook\AzureFacebookAzureDeploy\Sources\AzureFacebook\TfsBuild\deploy.ps1 C:\Builds\1\AzureFacebook\AzureFacebookAzureDeploy\Binaries\Release\ azurefacebook
</DeployCommand>

I wont go through the entire powershell script since it is documented here: Windows Azure Service Management CmdLets , but I will show you what I changed.  First I created some variables that i could pass in from the command line so that I could reuse this script on all of our Azure Projects.

$buildPath = $args[0] 
$servicename = $args[1]
$package = $buildPath + $servicename + ".cspkg"
$config = $buildPath + "ServiceConfiguration.cscfg"
$a = Get-Date
$buildLabel = $a.ToShortDateString() + "-" + $a.ToShortTimeString()

So now when it deploys it will create a label with the date and time it was deployed which is very useful when in Azure so you can see the last time you deployed.

You can download these scripts on our new Project on Codeplex that I worked with Microsoft on called the Facebook Azure ToolkitScott Densmore helped me create this awesome framework that makes it much easier to write apps for Azure.  There are a lot of useful libraries and scripts in that project that have nothing to do with Facebook, but more for Azure.  We are probably going to create another project on Codeplex that is just an Azure Toolkit.  This build script will be more refactored in the future, but wanted to get it out now for those looking to do this now.  More to come…

 | 
Tuesday, March 16, 2010 10:32:30 AM UTC #     |  Trackback

 

Proposed Session at MIX 10 on Facebook in .NET#

I proposed a session for MIX10 this year on How to develop Facebook apps in .NET and deploying them to Azure.  The last 6 months have been very hectic with delivering 3 highly scalable Facebook apps in Azure.  I spoke at PDC 09 this year during a lunch session, which was a great time.  Not as many people showed up as I thought, but 100 people is still a lot especially when there were thousands of poeple waiting in line for their laptops during that lunch.  Bad timing I guess, but it was a great first time speaking at an event like that.  You can see what i talked about here: http://microsoftpdc.com/Sessions/SVC32 I am the first 20 minutes talking about our app that we did for Outback Steakhouse.

After I did a session two months ago at Tampa Code Camp on Facebook app development in .NET, I realized there were a lot of people who wanted to learn about this stuff.  So I decided to submit a session to MIX10 this year and am very excited to be able to present there if I get enough votes.  :)  Hope to see you at Mix if you and I are lucky enough to go!

Mix10_Vote_grn_240

Wednesday, January 13, 2010 7:47:04 AM UTC #     |  Trackback

 

PdfResult a custom ActionResult in ASP.NET MVC#

I have been very bad about not blogging and not posting code from my recent talks.  For that I apologize.  Let me say just one thing on that.  4 kids, ADD, and shiny new toys. :)

Ok, so several people have asked about generating pdf’s from html and css.  At work, we needed this for receipts for registration among other things.  We found a great tool from Winnovative Software that works great with css and html and spitting out an almost perfect pdf. 

We are using mvc in our solution, so we decided to come up with a custom ActionResult so that it would make it very easy to return a pdf from an action call.

Here is what the action looks like:

public PdfResult PdfForm()
        {
            string html = this.CaptureActionHtml(this, c => (ViewResult)c.PrintForm());

            return new PdfResult(html, "PdfForm", true);
        }

        public ActionResult PrintForm()
        {
            var db = new NorthwindDataContext();
            
            List<Customer> customers = db.Customers.ToList<Customer>();

            ViewData["customers"] = customers;
            return View("PrintForm");
        }

 

Notice the CaptureActionHtml.  I found this code on this blog post as I was trying to figure out a way to use asp.net mvc as the template engine to save time for generating the html which the html to pdf tool needed.

Here is the CaptureActionHtml class:

using System;
using System.IO;
using System.Web;
using System.Web.Mvc;

namespace HtmlHelperExamples
{
    public static class ControllerExtensions
    {
        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The controller</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this TController controller,
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            return controller.CaptureActionHtml(controller, null, action);
        }

        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The controller</param>
        /// <param name="masterPageName">The master page to use for the view</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this TController controller,
            string masterPageName,
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            return controller.CaptureActionHtml(controller, masterPageName, action);
        }

        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The current controller</param>
        /// <param name="targetController">The controller which has the action to execute</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this Controller controller,
            TController targetController, 
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            return controller.CaptureActionHtml(targetController, null, action);
        }

        /// <summary>
        /// Captures the HTML output by a controller action that returns a ViewResult
        /// </summary>
        /// <typeparam name="TController">The type of controller to execute the action on</typeparam>
        /// <param name="controller">The current controller</param>
        /// <param name="targetController">The controller which has the action to execute</param>
        /// <param name="masterPageName">The name of the master page for the view</param>
        /// <param name="action">The action to execute</param>
        /// <returns>The HTML output from the view</returns>
        public static string CaptureActionHtml<TController>(
            this Controller controller,
            TController targetController, 
            string masterPageName,
            Func<TController, ViewResult> action)
            where TController : Controller
        {
            if (controller == null)
            {
                throw new ArgumentNullException("controller");
            }
            if (targetController == null)
            {
                throw new ArgumentNullException("targetController");
            }
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            // pass the current controller context to orderController
            var controllerContext = controller.ControllerContext;
            targetController.ControllerContext = controllerContext;

            // replace the current context with a new context that writes to a string writer
            var existingContext = System.Web.HttpContext.Current;
            var writer = new StringWriter();
            var response = new HttpResponse(writer);
            var context = new HttpContext(existingContext.Request, response) {User = existingContext.User};
            System.Web.HttpContext.Current = context;

            // execute the action
            var viewResult = action(targetController);

            // change the master page name
            if (masterPageName != null)
            {
                viewResult.MasterName = masterPageName;
            }

            // we have to set the controller route value to the name of the controller we want to execute
            // because the ViewLocator class uses this to find the correct view
            var oldController = controllerContext.RouteData.Values["controller"];
            controllerContext.RouteData.Values["controller"] = typeof(TController).Name.Replace("Controller", "");

            // execute the result
            viewResult.ExecuteResult(controllerContext);

            // restore the old route data
            controllerContext.RouteData.Values["controller"] = oldController;

            // restore the old context
            System.Web.HttpContext.Current = existingContext;

            return writer.ToString();
        }
    }
}

Here is the PdfResult class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Winnovative.WnvHtmlConvert;
using System.Text.RegularExpressions;

namespace System.Web.Mvc
{
    public class PdfResult : ViewResult
    {
        public string ContentType { get; set; }
        public string Content { get; set; }
        public string OutputFileName { get; set; }
        public bool ReturnAsAttachment { get; set; }

        public PdfResult(string html, string outputFileName, bool returnAsAttachment)
        {
            // ViewResult vr = ar as ViewResult;
            
            this.ContentType = "application/pdf";
            this.Content = html;
            this.OutputFileName = outputFileName;
            this.ReturnAsAttachment = returnAsAttachment;
        }
        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.ContentType = ContentType;
            
            string baseURL = "";
            string htmlString = this.Content;

            bool selectablePDF = true;

            // Create the PDF converter. Optionally you can specify the virtual browser width as parameter.
            //1024 pixels is default, 0 means autodetect
            PdfConverter pdfConverter = new PdfConverter();

            // set the license key
            pdfConverter.LicenseKey = "yourkeyhere";

            // set the converter options
            pdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4;
            pdfConverter.PdfDocumentOptions.PdfCompressionLevel = PdfCompressionLevel.Normal;
            pdfConverter.PdfDocumentOptions.PdfPageOrientation = PDFPageOrientation.Portrait;
            pdfConverter.PdfDocumentOptions.ShowHeader = false;
            pdfConverter.PdfDocumentOptions.ShowFooter = false;

            // set to generate selectable pdf or a pdf with embedded image
            pdfConverter.PdfDocumentOptions.GenerateSelectablePdf = selectablePDF;

            // Performs the conversion and get the pdf document bytes that you can further
            // save to a file or send as a browser response
            // The baseURL parameterhelps the converter to get the CSS files and images
            // referenced by a relative URL in the HTML string. This option has efect only
            // if the HTML string contains a valid HEAD tag.
            // The converter will automatically inserts a <BASE HREF="baseURL"> tag.
            byte[] pdfBytes = null;

            if (baseURL.Length > 0)
            {
                pdfBytes = pdfConverter.GetPdfBytesFromHtmlString(htmlString, baseURL);
            }
            else
            {
                pdfBytes = pdfConverter.GetPdfBytesFromHtmlString(htmlString);
            }

            // send the PDF document as a response to the browser for download
            // System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
            context.HttpContext.Response.Clear();

            // this.OutputFileName = Regex.Replace(this.OutputFileName, " ", "_", RegexOptions.IgnoreCase);
            // this.OutputFileName = StringHelper.StripNonAlphaNumeric(this.OutputFileName);

            context.HttpContext.Response.AddHeader("Content-Type", "application/pdf");

            if (this.ReturnAsAttachment)
            {
                context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=" + this.OutputFileName + ".pdf; size=" + pdfBytes.Length.ToString());
            }

            context.HttpContext.Response.Flush();
            context.HttpContext.Response.BinaryWrite(pdfBytes);
            context.HttpContext.Response.Flush();
            context.HttpContext.Response.End();

        }
    }

}

 

Hopefully this will help those of you who are wanting to generate the pdf’s using html and css along with using the default mvc view engine as your template engine. Enjoy!

Tuesday, October 06, 2009 8:20:29 AM UTC #     |  Trackback

 

IEnumerable Extension Method for AutoMapper#

I have been using AutoMapper for a few projects lately and just love its power and ease of use. My projects have become not only simpler to manage, but easier to do the right thing. What I mean by right thing, is creating ViewModels and Domain objects in my ASP.NET MVC projects. Although it seems like extra work to create multiple classes that seem to do what seems like the same thing, down the road it is a much better way to do things because of maintainability of views and domain logic not interfering. I am not going to get into the reason you would do this, but you can find out more here. Jimmy Bogard has a great article here as to why ViewModels are so important.

Sometimes when you do not want to have to create your maps ahead of time, it can be useful to use an extension method on IEnumerable which will work with IQueryable and any other Interface that implements IEnumerable .

An example is to map a complex query to a complex domain model. For instance, lets say I want to do a complicated db query using linq:

var q = from c in db.Customers
        select new { c.CompanyName, c.ContactName, Orders = (from order in db.Orders where order.CustomerID == c.CustomerID select order) };

AutoMapperHelper.TryCreateMap<Order, MyOrder>();
var a = q.ToModelList<ComplexCustomer>();

And here is the ComplexCustomer class that AutoMapper maps to:

public class ComplexCustomer
    {
        public string CompanyName { get; set; }
        public string ContactName { get; set; }
        public List<MyOrder> Orders { get; set; }
    }

Notice the extension Method: ToModelList(). This will execute the query to a list then automap it dynamically to the anonymous type or a defined type.

Here are the extension methods:

public static IList<TDestination> ToModelList<TDestination>(this IEnumerable query)
       {
           var output = new List<TDestination>();
           var sourceType = query.GetType().GetGenericArguments()[0];
           var destType = output.GetType().GetGenericArguments()[0];

           foreach (var src in query)
           {
               var mySrc = Mapper.DynamicMap(src, sourceType, destType);
               output.Add(Mapper.DynamicMap<TDestination>(mySrc));
           }

           return output;
       }
Code Snippet
  1. public static IList<TDestination> ToModelList<TDestination>(this IEnumerable query)
  2.         {
  3.             var output = new List<TDestination>();
  4.             var sourceType = query.GetType().GetGenericArguments()[0];
  5.             var destType = output.GetType().GetGenericArguments()[0];
  6.             foreach (var src in query)
  7.             {
  8.                 var mySrc = Mapper.DynamicMap(src, sourceType, destType);
  9.                 output.Add(Mapper.DynamicMap<TDestination>(mySrc));
  10.             }
  11.             return output;
  12.         \

There are two ways to use this extension, one is to tell the extension both the source and destination generic classes or just pass in the destination and it will use dynamic mapping to figure out what the source is. Notice that there also is a AutoMapperHelper class which helps to find out if the map you want is already in memory since AutoMapper stores the maps statically. We found that by not doing this it created a performance issue.

All in all, we are loving AutoMapper and I hope that others find this extension very useful. I have already used it with SubSonic 3, EF 4 and Action Filter Atrributes in an ASP.NET MVC Project.

Friday, July 10, 2009 8:38:52 AM UTC #     |  Trackback

 

Entity Framework and Creating a Reusable Abstraction#

I am currently working on an open source project called MyCodeCamp with Sean Chambers, Fabio Honigmann, and Esteban Garcia.  We decided to use ASP.NET MVC and Entity Framework (EF).  Although I use SubSonic 2.2 and 3 beta at work, I thought this might be a good time to learn other ORM type frameworks for comparison. I have used LINQ To SQL and NHibernate a little also, but am not an expert by any means.  And since we want this project to be accessible to as many as possible, we thought Entity Framework would be a good choice seeing as Linq2Sql is getting folded into Entity Framework anyway.

So, I don’t really know how most people use EF, but coming from working on SubSonic 3, I have some habits that I would like to keep, particularly, using a Repository<T> like pattern.  After looking at all the code and classes I would have to write if I did the traditional, IClassRepository and ClassRepository, I decided to make Repository<T> work kind of like it does in SubSonic 3 with SubSonicRepository<T>.  This was not as easy as I thought.

First problem is when you want to update the model, you need to open up the .edmx file in the designer which sometimes does not open and you have to reboot Visual Studio.  And if you make major changes to your data model, you are better off deleting the file and recreating it.  Now I don’t think that would go over to well if you actually used it to do your mappings of data to entity models, but I am not using Entity Framework that way.  I think it was their intention to use it more of as a mapper, but I think I have found a much easier and scalable way of mapping data to domain objects by using AutoMapper.  We use AutoMapper at work with SubSonic 3 and we just love it.  I won’t go into everything it does, but it is by far the best project out there for mapping objects to other objects.

So here is an example of how I am getting an entity object, then mapping it to a domain object.

public class Repository<T> : IRepository<T>
    {
        private MyCodeCamp.Data.MyCodeCampEntities context;
        public Repository()
        {
            context = new MyCodeCamp.Data.MyCodeCampEntities();

        }

        public T GetById(Int32 id)
        {
            var tableName = typeof(T).Name;
            var key = new EntityKey("MyCodeCampEntities." + tableName, "Id", id);
            var r = (T)context.GetObjectByKey(key);

            return r;
        }
    }

Notice, since I am using T, I need to use reflection to get the Entity Name, or table name.  Then this data returns to a BaseService<TModel, T>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AutoMapper;
using MyCodeCamp.Data;

namespace MyCodeCamp.Domain.Services
{
     public abstract class BaseService<TModel, T>
        where TModel : new()
        where T : new()
    {
         public Repository<T> _repo;

         protected BaseService()
        {
            _repo = new Repository<T>();
            // Cache maps
            var tm = Mapper.FindTypeMapFor<T, TModel>();
            if (tm == null)
            {
                Mapper.CreateMap<T, TModel>();
            }

            tm = Mapper.FindTypeMapFor<TModel, T>();
            if (tm == null)
            {
                Mapper.CreateMap<TModel, T>();
            }
        }

         public virtual TModel GetById(Int32 id)
         {
             var item = _repo.GetById(id);
             var model = Map(item);
             return model;
         }

        public virtual TModel Map(T d)
        {
            return Mapper.Map<T, TModel>(d);
        }


    
    }
}

Now for the service that derives form the BaseService:

public class VenueService : BaseService<Model.Venue, Data.Venue>
    {
        public VenueService()
        {
           
        }
        
        public List<Model.Venue> GetByCity(string city)
        {
            var result = _repo.Find(v => v.City == city);
            var venues = result.ToList();
            var venueModels = Map(venues);
            return venueModels;
        }

        
    }

As you can see the Code is very clean and simple to read.  What is nice about going down this road with the AutoMapper is that mapping is completely automated and I don’t have to remap anything if I change properties or add them to the data model.  All I need to do is make sure the Property is on the domain model, then it will get mapped.  Also it will map by convention also, so if you have a Complex type as a property, like, Venue.Room.Name it would automatically map to a flattened dto like Venue.RoomName.  There are a ton of other conventions also, but you should go download AutoMapper and look at the tests to see all of the possibilities.

The next big issue I ran into was that the data was not getting updated when I would pass a detached object to the EF context.  Since I was creating the object that needed to get passed in outside of the ObjectContext scope, I needed to get the EF ObjectStateManager to recognize that the Entity Object had changed and to persist it.  I again had to use a little bit of reflection, but after I understood how EF handled things, it made more sense.  It was quite frustrating for a few hours trying to figure out why EF was not persisting updates and only inserts.  As you can see with the code below I needed to get the value of the Entity Key and the hydrate the entity object so that the ObjectStateManager knew that the data had been changed.

public int Update(T o)
       {
           var tableName = typeof(T).Name;

           // Need to get object out of ObjectStateManager, then set it so the dbcontext knows to persist changes
           var Id = GetPrimaryKeyValue(o);
           T currentObject = GetById(Id);
           currentObject = o;

           context.ApplyPropertyChanges(tableName, currentObject);

           return context.SaveChanges();
       }

       private int GetPrimaryKeyValue(T o)
       {
           int Id = 0;
           var properties = typeof(T).GetProperties();
           foreach (PropertyInfo p in properties)
           {
               if (string.Compare(p.Name, "Id", true) == 0)
               {
                   var r = p.GetValue(o, null).ToString();
                   Id = int.Parse(r);
                   break;
               }
           }
           return Id;
       }
All in all, I don’t mind EF for the Data Access Mapping, and the way it is currently abstracted in our project, it could easily be switched out for Linq To Sql, Subsonic, or any other ORM that uses LINQ to access its data.  I think the best way to use Data Mapping technologies in the future is control your own mapping by using tools such as AutoMapper so that you are not locked in to one way of getting your data out of your database. 
Monday, May 18, 2009 4:39:27 AM UTC #     |  Trackback

 

Modifying a compile asp.net assembly when no longer have source#

So while I was at the MVP Summit, an old client got a hold of me and said there was a weird error on the site when a user was trying to post something.  He sent me a screenshot and it said could not login as sa to sql server.  I remoted into the server where they had moved the application and looked in the web.config file and did not see any connection string that had sa as the user name.  So I was stumped.  I began to look at the stack trace and realized which assembly this was coming from.  This happened to be the only assembly which did not have the source code on the server.  I wrote the app over 6 years ago and the laptop the source was on had recently had a failed hard drive.

Anyway, it was a vb.net 1.1 app from visual studio 2003.  Yes I used to do a little VB. :)  So I realized that there must have been a connection string hard coded in the assembly where the stack trace was coming from.  Oh no!  How was i going to fix this without changing the sa password on their new host which was not really an option? 

First thing I did was download reflector here. I opened the assembly and did see the hard code connection string.  Man what an idiot for doing that.  Don’t know why I did that at the time, but not a very smart move. So I was stuck.  How do I edit an assembly without having to export all the code from reflector, find visual studio 2003 and run it in a virtual, download the rest of the app and pray that I could get it to work.  Well i searched for modifying a .net assembly and found this: Reflexil - http://sebastien.lebreton.free.fr/reflexil/ . It is a plug-in that works inside of reflector that allows the modification of the code in the assembly.  So i downloaded it opened the assembly, changed the connection string code and then saved it.  The .dll ended up being a third the size, but still worked after deploying it to the server.  I was shocked.  I just had edited a vb.net 1.1 assembly on a windows 7 laptop using reflector while in a session during the MVP summit.  Pretty cool I think.  Saved me a whole day of figuring out how to run visual studio 2003 and get that code compiled again.

Wednesday, March 25, 2009 7:42:51 AM UTC #     |  Trackback

 

Windows 7 and My 2 year old Laptop#

I have owned a Dell Inspiron 9400 for almost 2 years with Vista Ultimate and have enjoyed it for the most part.  I had some issues with wireless and getting the sluggish feeling after I had visual studio, 20 browser tabs open, iis 7, sql server, etc. all open at the same time.  Of course I thought, well i have a lot of stuff running at same time so of course it will be slower.  Well now with Windows 7 I have not one wireless issue, speed is crazy faster and I  am still only using 1 gb of ram of 2 gb available. 

I am absolutely shocked a how much better I like my laptop.  I have a 8 Gb Vista 64 desktop at home, so my laptop is always going to seem sluggish, but now I really like using my laptop.  I am not looking forward to having to wipe it again when the beta expires, but is well worth the joy i now get from my laptop. 

Windows7DesktopSmall

I love the new task bar and my favorites always being down there.  I can’t remember if I have even done a full reboot in a month.  Oh if you are going to try this at home, make sure to do a clean install. 

Tuesday, February 24, 2009 9:00:35 AM UTC #     |  Trackback

 

Enabling 301 redirects on IIS 7 on Windows server 2008#

I was stumped the other day as to why i could not get a 301 redirect in from site.com to www.site.com on IIS 7.  After much looking around I found out that you need to enable this feature in the server manager. 

image

Then you need to go back to the IIS node that you want to enable 301 redirect for:

 

image

And then set the values for your redirect:

image

If you notice what is also cool is that it will redirect addresses relative to the domain and not just to the root (i.e site.com/oldfile.htm will redirect to www.site.com/oldfile.htm

Hope this helps someone, cause it was not very intuitive for me to find out how to do it since the feature was not installed by default.

Thursday, February 05, 2009 10:37:27 AM UTC #     |  Trackback

 

 

All content © 2014, Jim Zimmerman
Book
New Book
Links to me
On this page
Sponsors
Calendar
<April 2014>
SunMonTueWedThuFriSat
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910
Archives
Tags
Blogroll OPML
Technorati
Favorite Links
Disclaimer

Powered by: newtelligence dasBlog 1.9.6264.0

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

Send mail to the author(s) E-mail