Wednesday, July 30, 2014

Dedicated IP address on Azure Websites

When you share the IP address with some other websites / clients / customers (like it happens on a multi-tenant environment), you could have some problems like, for instance, have your IP blacklisted because of other sites' content.

The only reliable way to resolve this and protect your site from a recurrence is to configure your site with a dedicated IP. This means that the site will be using its own IP, which would not be shared with other sites. 

In Azure, you can easily get a dedicated IP by configuring IP SSL. This option is available only to the sites in the Standard tier, but if you’re using a custom Domain on your site, there are some extra considerations.

If you are using a custom domain and have a CNAME record pointing from it to the site’s name in Azure (for example, mysite.azurewebsites.net), then it’s rather simple – just change the record with your DNS provider and then configure IP-SSL.

If, on the other hand, you are using an A-record to resolve the host name to an IP, it's recommended to follow these steps:

  1. Change your hostname mapping (i.e. www.mysite.com) from an A record to a CNAME pointing to your Microsoft Azure Web Site (i.e. mysite.azurewebsites.net).  This should have no downtime as it will be pointing to the same IP. Wait some time for DNS replication to take place.
  2. Upload a certificate for www.mysite.com to your website. This can be accomplished under Domain names in the Configure tab. Usually, you would have to purchase the Certificate from a Certificate provider, but if you don’t intend to actually use SSL, you can use a self-signed certificate which is easy to generate and won’t cost you a dime.
  3. Configure an IP Based SSL binding for www.mysite.com. This option is available under SSL Binding in the Configure tab. See the section Configure SSL in the Azure guide for SSL.

Tuesday, July 22, 2014

Visual Studio Online now supports Azure Active Directory

Yesterday the Microsoft's vsalm team began deployment of the sprint 68 work.

The biggest thing in the announcement is the next step in the rollout of Azure Active Directory (AAD) support in VS Online.  They started this journey back in May with the very first flicker of AAD support at the Build conference.  Then they added more support at TechEd but they've stay pretty quiet about it because, until this week, there was no way to convert and existing account to AAD.  With this deployment they’ve enabled it.  Officially it’s in preview and you have to ask to get access to do it but they’re accepting all requests so it’s nothing more than a speed bump to keep too big a rush from happening all at once.  With these last set of changes, you can:


  • Associate your OrgID (AAD/AD credentials) with your MSDN subscription, if you have one, and use that to grant your VSO license
  • Create a new account bound to an AAD tenant
  • Bind an existing account to an AAD tenant
  • Unbind an account from an AAD tenant
  • Log in with either a Microsoft Account or and OrgID (AAD only or synchronized from you on prem Active Directory) giving you single sign-on with your corporate credentials, Office 365, etc.
To see all the details about AD support and other things included in the update, read the original post on MSCD by Brian Harry.

Monday, July 14, 2014

ASP.net MVC ActionLink with Image: Part 3 (Ajax)

In my previous posts we've seen how to implement some custom helpers to add  Bootstap Glyphs or Images to ActionLinks.

Now we're going to see how to do the same thing but with Ajax support too.

The basic things to do is to build the html code taking care of all the "ajax-related stuff" that the normal Ajax.ActionLink helper adds.

In this example I used the glyph as image, but you can use the same approach also with the normal images.

/// <summary>
/// Create an Ajax.ActionLink with an associated glyphicon
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="linkText"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <param name="glyphicon"></param>
/// <param name="routeValues"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString ImageActionLink(this AjaxHelper ajaxHelper, string linkText, string actionName, string controllerName, string glyphicon, AjaxOptions ajaxOptions, RouteValueDictionary routeValues = null, object htmlAttributes = null)
{
 //Example of result:           
 //<a id="btnShow" href="/Customers/ShowArtworks?customerId=1" data-ajax-update="#pnlArtworks" data-ajax-success="jsSuccess" 
 //data-ajax-mode="replace" data-ajax-method="POST" data-ajax-failure="jsFailure" data-ajax-confirm="confirm" data-ajax-complete="jsComplete" 
 //data-ajax-begin="jsBegin" data-ajax="true">
 //  <i class="glyphicon glyphicon-pencil"></i>
 //  <span>Edit</span>
 //</a>

 var builderI = new TagBuilder("i");
 builderI.MergeAttribute("class", "glyphicon " + glyphicon);
 string iTag = builderI.ToString(TagRenderMode.Normal);

 string spanTag = "";
 if (!string.IsNullOrEmpty(linkText))
 {
  var builderSPAN = new TagBuilder("span");
  builderSPAN.InnerHtml = " " + linkText;
  spanTag = builderSPAN.ToString(TagRenderMode.Normal);
 }

 //Create the "a" tag that wraps
 var builderA = new TagBuilder("a");

 var requestContext = HttpContext.Current.Request.RequestContext;
 var uh = new UrlHelper(requestContext);

 builderA.MergeAttribute("href", uh.Action(actionName, controllerName, routeValues));

 //Ajax section
 builderA.MergeAttribute("data-ajax", "true");
 builderA.MergeAttribute("data-ajax-update", ajaxOptions.UpdateTargetId.StartsWith("#") ? ajaxOptions.UpdateTargetId : "#" + ajaxOptions.UpdateTargetId);
   
 if (!string.IsNullOrEmpty(ajaxOptions.InsertionMode.ToString()))
  builderA.MergeAttribute("data-ajax-mode", ajaxOptions.InsertionMode.ToString());            
 
 if (!string.IsNullOrEmpty(ajaxOptions.OnBegin))
  builderA.MergeAttribute("data-ajax-begin", ajaxOptions.OnBegin);
 
 if (!string.IsNullOrEmpty(ajaxOptions.OnComplete))
  builderA.MergeAttribute("data-ajax-complete", ajaxOptions.OnComplete);
   
 if (!string.IsNullOrEmpty(ajaxOptions.OnFailure))
  builderA.MergeAttribute("data-ajax-failure", ajaxOptions.OnFailure);
   
 if (!string.IsNullOrEmpty(ajaxOptions.OnSuccess))
  builderA.MergeAttribute("data-ajax-success", ajaxOptions.OnSuccess);
   
 if (!string.IsNullOrEmpty(ajaxOptions.Confirm))
  builderA.MergeAttribute("data-ajax-confirm", ajaxOptions.Confirm);
  
 if (!string.IsNullOrEmpty(ajaxOptions.HttpMethod))
  builderA.MergeAttribute("data-ajax-method", ajaxOptions.HttpMethod);

 if (htmlAttributes != null)
 {
  IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);
  builderA.MergeAttributes(attributes);
 }

 builderA.InnerHtml = iTag + spanTag;

 return new MvcHtmlString(builderA.ToString(TagRenderMode.Normal));
}


As you can see, the code is similar to the one we've seen in the other posts but with the exception of the fact we are extending an "AjaxHelper" insetead of  an "HtmlHelper" and the add of the "ajax section"

Thursday, July 10, 2014

Visual Studio Online licenses will change (in better)

Through the fall and spring, Visual Studio Online transitioned from Preview to General Availability.  That process included changes to branding, the SLA, the announcement of pricing, the end of the early adopter program and more.

Now, the VSO/TFS team has decided to roll out these 2 major licensing changes in the next couple of months:

  • any VS Online account will be able to have an unlimited number of “Stakeholder” users with access to the a subset of functionality, at no charge.
  • the Visual Studio Online Advanced plan will include access to all of the Test hub functionalities 


The team is working hard to implement these licensing changes now and the expectation is that they’ve got about 2 sprints of work to do to get it all finished.  That would put the effective date somewhere in the neighborhood of mid-August.

In general, the team goal is to keep the licensing for VS Online and Team Foundation Server as “parallel” as they can – to limit how confusing it could be.  As a result, they will be evolving the current “Work Item Web Access” TFS CAL exemption (currently known as “Limited” users in TFS) to match the “Stakeholder” capabilities.  That will result in significantly more functionality available to TFS users without CALs.  The hope is to get that change made for Team Foundation Server 2013 Update 4.


Here you can find the original announcement by Brian Harry:
http://blogs.msdn.com/b/bharry/archive/2014/07/09/upcoming-vs-online-licensing-changes.aspx

Wednesday, July 9, 2014

ASP.net MVC ActionLink with Image: Part 2 (using Images)

In my previous post I talked about creating a custom helper to render an ActionLink with a Glyph image.

In this post I will show how to create a similar helper but using "normal" images instead of bootstrap glyphs.

/// <summary>
/// Create an ActionLink with an associated image
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="linkText"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <param name="imagePath"></param>
/// <param name="routeValues"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString ImageImgActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string imagePath, object routeValues = null, object htmlAttributes = null)
{
 //Exemple of result:
 //<a href="@Url.Action("Edit", new { id = Model.id_rod })">
 //  <i class="glyphicon glyphicon-pencil"></i>
 //  <span>Edit</span>
 //</a>

 if (imagePath.StartsWith("~/"))
 {
  imagePath = VirtualPathUtility.ToAbsolute(imagePath);
 }

 var builderImage = new TagBuilder("image");
 builderImage.MergeAttribute("src", imagePath);
 builderImage.MergeAttribute("alt", linkText);
 builderImage.MergeAttribute("style", "border=0");
 string imageTag = builderImage.ToString(TagRenderMode.SelfClosing);

 string spanTag = "";
 if (!string.IsNullOrEmpty(linkText))
 {
  var builderSPAN = new TagBuilder("span");
  builderSPAN.InnerHtml = " " + linkText;
  spanTag = builderSPAN.ToString(TagRenderMode.Normal);
 }

 //Create the "a" tag that wraps
 var builderA = new TagBuilder("a");

 var requestContext = HttpContext.Current.Request.RequestContext;
 var uh = new UrlHelper(requestContext);

 builderA.MergeAttribute("href", uh.Action(actionName, controllerName, routeValues));

 if (htmlAttributes != null)
 {
  IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);
  builderA.MergeAttributes(attributes);
 }

 builderA.InnerHtml = imageTag + spanTag;

 return new MvcHtmlString(builderA.ToString(TagRenderMode.Normal));
}


You can pass to the helper both absolute urls or relative urls (as imagePath) so it gives you total flexibility.

Monday, July 7, 2014

ASP.net MVC ActionLink with Image: Part 1 (using Glyph)

If you are using ASP.net MVC you surely know that there is an helpful helper to create a link that points to an Action of a controller: it's the Html.ActionLink.

You can use this helper only with text, but what about if you want to add to the link a glyph image, like in this example?



Well, the "fast&dirty" answer is to write some html directly in the cshtml page. Something like:

<a href="@Url.Action("Edit", new { id = Model.id })">
  <i class="glyphicon glyphicon-pencil"></i>
  <span>Edit</span>
</a>


This approach is faster that any other, if you need to have it only in few places. But what about if you have to use it spread all around you application (as in my case?). You will have to copy&paste the code all around and then change it. Not so good...

The better way to do it, in this case, is to write a custom helper that will do it for you.

/// <summary>
/// Create an ActionLink with an associated glyphicon
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="linkText"></param>
/// <param name="actionName"></param>
/// <param name="controllerName"></param>
/// <param name="glyphicon"></param>
/// <param name="routeValues"></param>
/// <param name="htmlAttributes"></param>
/// <returns></returns>
public static MvcHtmlString ImageActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string glyphicon, object routeValues = null, object htmlAttributes = null)
{
 //Exemple of result:
 //<a href="@Url.Action("Edit", new { id = Model.id_rod })">
 //  <i class="glyphicon glyphicon-pencil"></i>
 //  <span>Edit</span>
 //</a>

 var builderI = new TagBuilder("i");
 builderI.MergeAttribute("class", "glyphicon " + glyphicon);
 string iTag = builderI.ToString(TagRenderMode.Normal);

 string spanTag = "";
 if (!string.IsNullOrEmpty(linkText))
 {
  var builderSPAN = new TagBuilder("span");
  builderSPAN.InnerHtml = " " + linkText;
  spanTag = builderSPAN.ToString(TagRenderMode.Normal);
 }            

 //Create the "a" tag that wraps
 var builderA = new TagBuilder("a");

 var requestContext = HttpContext.Current.Request.RequestContext;
 var uh = new UrlHelper(requestContext);
 
 builderA.MergeAttribute("href", uh.Action(actionName, controllerName, routeValues));

 if (htmlAttributes != null)
 {
  IDictionary<string, object> attributes = new RouteValueDictionary(htmlAttributes);
  builderA.MergeAttributes(attributes);
 }
  
 builderA.InnerHtml = iTag + spanTag;
 
 return new MvcHtmlString(builderA.ToString(TagRenderMode.Normal));
}

At this point it will be possible to invoke the Html.ImageActionLink helper in the same way and with the same parameters that we will use with the "normal" Html.ActionLink plus the glyphicon class of the glyph image we wanna add to the link.

Wednesday, July 2, 2014

Delete work items from TFS or VSO

Have you ever created a bunch of work items that you decided later that you had to delete. Well I have… especially as a user of the TFS Integration Platform. And when things go wrong there they can really go wrong.

Now while you can put stuff into the “removed” state it is still hanging around cluttering up the place. The only way out of the box to remove items is to give the ID for each work item that you want to delete and execute the command line for each one:

witadmin destroywi /collection:CollectionURL /id:id [/noprompt]

Well that’s just great unless you have a couple of thousand things to delete. 
So I've written a little bit of code to do it for me; in this example I created a small console program but you can use the same code in any kind of project.

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

[...]

TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("http://your_tfs_url:8080/tfs/CollectionName"));
WorkItemStore store = tpc.GetService();

string query = @"SELECT [System.Id] FROM WorkItems WHERE [System.TeamProject] = 'projectName'  AND  [System.AreaPath] UNDER 'projectName\_TOBEDELETED' ORDER BY [System.Id]";

WorkItemCollection wis = store.Query(query);
var wisIds = wis.Select( wi => wi.Id);

Console.WriteLine(string.Format("DESTROY {0} work items (they really can't be resurrected): y/n?", wis.Count));
ConsoleKeyInfo cki = Console.ReadKey();
Console.WriteLine();

if (cki.Key.ToString().ToLower() == "y")
{
 try
 {
  Console.WriteLine("Deleting....");
  var items = store.DestroyWorkItems(wisIds.ToArray());
  Console.WriteLine("DONE");
  foreach (var item in items)
  {
   Console.WriteLine(item.ToString());
  }
 }
 catch (Exception ex)
 {
  [...]
 }

}

Console.WriteLine("Finished");


The first thing that you may notice is that I search for items in a specific area path. I use _TOBEDELETED as it is obvious what is going to happen to things that end up there. Although I did work with a user who complained that all his files had gone missing. When asked where he kept them he pointed at the recycle bin on his desktop!

Anyhow, just in case you made a mistake it will let you know how many work items that you are deleting. It’s a simple check but I have had it say "100000" work items... AS you can imagine I very carefully terminated the program (never trust the 'no' option).