<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Pranab Paul's Blog - Development Tips on Azure, SharePoint, Office</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/pranab/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/pranab/feed.xml</link>
    <description>PaaS, IaaS, Web App, Mobile App, API App, APIM, ASE, Web Parts, Workflow, InfoPath, Features, Site Definition, Event Receivers, Excel Services, Business Connectivity Services (BCS), LinQ to SharePoint, Sandbox, Silverlight, WCF, Search, BI, PPS, OC Automaion, UCCA, UCMA</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:24:19 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Best Practices - Azure App Service and Java Application</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/best-practices-azure-app-service-and-java-application</link>
      <pubDate>Mon, 22 Aug 2016 12:27:17 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/?p=625</guid>
      <description><![CDATA[Recently we migrated an application used by 170 thousand users to Azure PaaS. This application has 3...]]></description>
      <content:encoded><![CDATA[Recently we migrated an application used by 170 thousand users to Azure PaaS. This application has 3 tier model. The web tier uses HTML5 and ReactJS. The application tier uses Java and for Database we used Azure SQL DB. There was good amount of learning and I thought I should share those for everyone’s benefit.
<ol>
 	<li><strong>Environment</strong> – In our case the Java application was providing REST API which were in turn consumed by the Web Layer (ReactJS). This setup provides stateless transactions. We used Web App to host the Java APIs. It could be API App as well. We thought of using App Service Environment (ASE) in the beginning but continued with multi-tenant environment instead. This decision was taken after a discussion with Azure product team and they told us not to use ASE for Java applications. This is due to the current performance issues Java applications have with ASE. This I believe will be taken care before EOY 2016 and ASE should be suitable for Java as well.</li>
 	<li><strong>Connectivity between</strong> <strong>services</strong> – It is very important that you use connection pooling for your SQL DB. Find out what is the max no. of connection your SQL DB can hold. In our case it was 2000 and we were using JDBC/Hibernate to connect to SQL DB. Hence we used 100 max connection pool settings in our JDBC so that even we scale up to 20 instances of Web App (which is max no. of instances in case of Web App premiere), it works perfectly.
There are high possibilities of transient faults between service calls hence retry logic is something is a must in your code. Utilize Retry pattern as described here (<a href="https://msdn.microsoft.com/en-us/library/dn589788.aspx">https://msdn.microsoft.com/en-us/library/dn589788.aspx</a>) and in some cases, if you are using an external service and you are not very sure about the responsiveness of the service, then Circuit Breaker pattern should also be useful (<a href="https://msdn.microsoft.com/en-us/library/dn589784.aspx">https://msdn.microsoft.com/en-us/library/dn589784.aspx</a>).</li>
 	<li><strong>Caching</strong> – For any type of data that is not frequently changes, usage of caching will do wonder in performance. We found Redis very useful in this regards. Although we have an example in Azure web site of using a library called Jedis (<a href="https://azure.microsoft.com/en-us/documentation/articles/cache-java-get-started/">https://azure.microsoft.com/en-us/documentation/articles/cache-java-get-started/</a>), we used another library called Lettuce as it has TLS option that Jedis didn’t have (at least at that point in time). I posted regarding this in my previous post: <a href="https://blogs.msdn.microsoft.com/pranab/2016/04/14/how-to-use-azure-redis-cache-with-java-using-lettuce/">https://blogs.msdn.microsoft.com/pranab/2016/04/14/how-to-use-azure-redis-cache-with-java-using-lettuce/</a></li>
 	<li><strong>Scalability</strong> – Azure App Service has the flexibility of auto-scale. We used the same in our production and it gave us great result as this application was seasonal in nature. But you should be very careful about configuring auto-scale. You need to decide whether the scale will it be CPU based, memory based or incoming request based. Please do extensive load test and then decide. Also make sure you planned for surge of incoming requests and have enough number of instances available at any point in time to tackle such situation. Otherwise, in case of seasonal application you can use fixed set of instances for the pick request days based on your test experience and then reduce to minimum no. of instances when that period is over.</li>
 	<li><strong>Special case with Hibernate</strong> – In case you are using JDBC + Hibernate, please make sure your SQL tables have nVarchar columns instead of Varchar columns. The reason is Hibernate “string” gets converted to nVarchar all the time. If you have Varchar in your table, then SQL DB will silently do implicit conversion between nVarchar and Varchar. And this will reduce the performance drastically.</li>
 	<li><strong>Last but not the least</strong> – test, test and test. All possible test especially load test is super critical to a successful implementation of Java application on Azure PaaS.</li>
</ol>]]></content:encoded>
    </item>
    <item>
      <title>How to use Azure Redis Cache with Java using Lettuce</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/how-to-use-azure-redis-cache-with-java-using-lettuce</link>
      <pubDate>Thu, 14 Apr 2016 18:32:09 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/?p=605</guid>
      <description><![CDATA[I was looking for an option of using Azure Redis cache with Java. I found the...]]></description>
      <content:encoded><![CDATA[I was looking for an option of using Azure Redis cache with Java. I found the article: https://azure.microsoft.com/en-us/documentation/articles/cache-java-get-started/.

This uses the Java client called Jedis. Unfortunately, till the time of writing this blog post, Jedis doesn't have SSL option and my customer needs SSL. Hence, I had to find a different client and found Lettuce (http://redis.paluch.biz/download.html). A good no. of experts within Microsoft also recommends the same. We already implemented Redis cache using Java and Lettuce client. For other's benefit, here are the steps.

1. Set up Redis cache as recommended in the above mentioned article. Only remember, we will use SSL port (6380) in this case.

2. In your code you need to include following JAR files. You can download them from Maven repository:

lettuce-4.1.1.Final.jar

netty-buffer-4.0.34.Final.jar

netty-codec-4.0.34.Final.jar

netty-common-4.0.34.Final.jar

netty-transport-4.0.34.Final.jar

netty-transport-native-epoll-4.0.34.Final.jar

netty-handler-4.0.34.Final.jar

guava-17.0.jar

commons-pool2-2.4.2.jar

LatencyUtils-2.0.3.jar

rxjava-1.1.0.jar

HdrHistogram-2.1.4.jar

3. And here is the sample code:

<strong>import</strong> java.util.concurrent.TimeUnit;

<strong>import</strong> com.lambdaworks.redis.RedisClient;

<strong>import</strong> com.lambdaworks.redis.RedisFuture;

<strong>import</strong> com.lambdaworks.redis.RedisURI;

<strong>import</strong> com.lambdaworks.redis.api.StatefulRedisConnection;

<strong>import</strong> com.lambdaworks.redis.api.async.RedisAsyncCommands;

<strong>import</strong> com.lambdaworks.redis.api.sync.RedisCommands;

&nbsp;

&nbsp;

<strong>public</strong> <strong>class</strong> Test {

&nbsp;

<strong>public</strong> <strong>static</strong> <strong>void</strong> main(String[] args) {

RedisURI redisURI = <strong>new</strong> RedisURI();

redisURI.setHost("your redis url");

redisURI.setPort(6380);

redisURI.setSsl(<strong>true</strong>);

redisURI.setPassword("&lt;your password&gt;");

RedisClient redisClient = RedisClient.<em>create</em>(redisURI);

StatefulRedisConnection&lt;String, String&gt; connection = redisClient.connect();

System.<strong><em>out</em></strong>.println("Connected to Redis using SSL");

&nbsp;

/*******************Sync options*****************************/

RedisCommands&lt;String, String&gt; syncCon = connection.sync();

syncCon.hset("fooTobar", "foo", "bar");

String value = syncCon.hget("fooTobar","foo");

System.<strong><em>out</em></strong>.println(value);

&nbsp;

/************************************************************/

&nbsp;

/*******************<span style="text-decoration: underline">Async</span> options*****************************/

RedisAsyncCommands&lt;String, String&gt; asyncCon = connection.async();

<strong>try</strong> {

RedisFuture&lt;String&gt; future = asyncCon.hget("fooTobar","foo");

String valueAsync = future.get(1, TimeUnit.<strong><em>MINUTES</em></strong>);

System.<strong><em>out</em></strong>.println(valueAsync);

} <strong>catch</strong> (Exception e) {

e.printStackTrace();

}

&nbsp;

/************************************************************/

connection.close();

redisClient.shutdown();

}

}

&nbsp;]]></content:encoded>
    </item>
    <item>
      <title>Sizing Elasticsearch on Azure IaaS</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/sizing-elasticsearch-on-azure-iaas</link>
      <pubDate>Wed, 23 Dec 2015 22:42:17 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2015/12/23/sizing-elasticsearch-on-azure-iaas/</guid>
      <description><![CDATA[Are you an architect? Does your work involve Azure IaaS and PaaS? Then sooner or later you will find...]]></description>
      <content:encoded><![CDATA[<p><span style="font-size: medium;">Are you an architect? Does your work involve Azure IaaS and PaaS? Then sooner or later you will find yourself in a situation where your customer will ask you this question (if not already did).</span></p>
<p><span style="font-size: medium;">Now, sizing is a tricky business. Primarily involves 2 parts &ndash; find an optimum server/VM and then find out how many. Let&rsquo;s take these one by one.</span></p>
<p><span style="font-size: medium;">In&nbsp;search world, there is no silver bullet for sizing and most of the time it&rsquo;s done by rigorous test and observation. For example, Microsoft&rsquo;s own SharePoint Enterprise Search &ndash; product team suggested some sizing benchmark based on no. of items to be crawled and indexed (10 million, 40 million and so on). This had been done based on good amount of tests conducted by product and other groups.</span></p>
<p><span style="font-size: medium;">In case of Elasticsearch, we have few information and observation provided on their website which may help us derive to some sizing idea.</span></p>
<p><span style="font-size: medium;">Let&rsquo;s look at the following article: <a href="https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fwww.elastic.co%2fguide%2fen%2felasticsearch%2fguide%2fcurrent%2fhardware.html&amp;data=01%7c01%7cpranabp%40064d.mgd.microsoft.com%7c1e5ee5cb187e4316eab608d30a9ed0aa%7c72f988bf86f141af91ab2d7cd011db47%7c1&amp;sdata=hfwkFcGGlYn%2bZvZ2pZ%2bhrHUkctvIxBmBLnCEmyxj6Jo%3d">https://www.elastic.co/guide/en/elasticsearch/guide/current/hardware.html</a>. Based on this we can derive the following:</span></p>
<ol>
<li><span style="font-size: medium;"><strong>Memory</strong>: It advises to use 64 GB. But in Azure world, we have 56 GB and 112 GB. 112 GB would be an overkill and as per the above article more than 64 GB is not advisable. So we stick to 56 GB.</span></li>
<li><span style="font-size: medium;"><strong>CPU:</strong> No definitive guide. We will choose 8 cores. One thing to be noticed here. It says between faster CPU and more core CPU, we should choose more cores. So 16 cores machine looks like better bet. But as we do not have specific info about &ldquo;sweet spot&rdquo; as with memory, let&rsquo;s start with 8 core.</span></li>
</ol>
<p><span style="font-size: medium;">Now, for Disk, let&rsquo;s see this: <a href="https://na01.safelinks.protection.outlook.com/?url=https%3a%2f%2fwww.elastic.co%2fblog%2fperformance-considerations-elasticsearch-indexing&amp;data=01%7c01%7cpranabp%40064d.mgd.microsoft.com%7c1e5ee5cb187e4316eab608d30a9ed0aa%7c72f988bf86f141af91ab2d7cd011db47%7c1&amp;sdata=500YGU03wyM701ABYJaFA2ndWZ6rHmgftEriOWndZmY%3d">https://www.elastic.co/blog/performance-considerations-elasticsearch-indexing</a>. Although no definitive guide on IOPS, but it is clearly mentioned and advised high speed SSDs to store index. That too, local SSDs are preferred in comparison to attached one like Premium storage. To store the data/log we can have regular Azure storage. Premium storage is not essential. At least not indicated anywhere or at least I didn&rsquo;t notice.</span></p>
<p><span style="font-size: medium;">This brings us to Azure VMs like DS 13 or D13 V2. Which has 8 core, 56 GB RAM, and 400 GB SSD local storage. In my opinion, this can be considered as a benchmark for my VMs. In other words, if we need to scale higher, we will scale out rather than scale up.</span></p>
<p><span style="font-size: medium;">Now, the question is how many VMs? Here I couldn&rsquo;t find any definitive guide. It looks like things are mostly done on trial and error basis. But for a production setup with Terabytes of data, I&rsquo;d recommend 3 node cluster to start with and then scale-out as required.&nbsp;</span></p>
<p><span style="font-size: medium;">Regarding the OS, I&rsquo;d vote for Ubuntu, this is only because I saw at least 2 customers successfully running Elasticsearch on Ubuntu on Azure IaaS. Here is a guide, though a bit old but still may be useful:&nbsp;<a href="http://code972.com/blog/2014/07/74-the-definitive-guide-for-elasticsearch-on-windows-azure">http://code972.com/blog/2014/07/74-the-definitive-guide-for-elasticsearch-on-windows-azure</a></span></p>
<p><span style="font-size: medium;">As correctly said in the last link mentioned, you don't need load balancer (Azure or 3rd party).</span></p>
<p><span style="font-size: medium;">At the end, a disclaimer,&nbsp;this article&nbsp;based on my experience with Elasticsearch and Azure. Your opinion and suggestions are most welcome.</span></p>]]></content:encoded>
    </item>
    <item>
      <title>VS 2013 Coded Web Performance Test with RAW JASON data in body</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/vs-2013-coded-web-performance-test-with-raw-jason-data-in-body</link>
      <pubDate>Tue, 12 May 2015 09:54:00 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2015/05/12/vs-2013-coded-web-performance-test-with-raw-jason-data-in-body/</guid>
      <description><![CDATA[I was working for a customer to run Web test and Load test on their Java based APIs hosted on Azure...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: verdana,geneva; font-size: medium;">I was working for a customer to run Web test and Load test on their Java based APIs hosted on Azure IaaS VMs. I was desperately looking for some coded Web test which will send custom header and will Post RAW data (JSON) in body. But couldn't locate any such example. Once created and tested by myself, thought it would be helpful for others:</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: medium;">using System;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">using System.Collections.Generic;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">using System.Text;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">using Microsoft.VisualStudio.TestTools.WebTesting;</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: medium;">namespace WebAndLoadTestProject2</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">{</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; [Priority(0)]</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; public class testCoded : WebTest</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public testCoded()</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.PreAuthenticate = true;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Proxy = "default";</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public override IEnumerator&lt;WebTestRequest&gt; GetRequestEnumerator()</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebTestRequest wtRequest = new WebTestRequest(<a href="https://www.contoso.com/APICollection/getFlightInfo/">https://www.contoso.com/APICollection/getFlightInfo/</a>);</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wtRequest.Timeout = 300;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wtRequest.Method = "POST";</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;wtRequest.Headers.Add(new WebTestRequestHeader("Content-Type", "application/json"));</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wtRequest.Headers.Add(new WebTestRequestHeader("Authorization", "bearer pranab.paul@contoso.com"));</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; StringHttpBody requestBody = new StringHttpBody();</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requestBody.ContentType = "application/json";</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requestBody.InsertByteOrderMark = false;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; requestBody.BodyString = @"{</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; ""itenaryType"":""international"",</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; ""routes"": [{</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ""endDate"":""30-05-2015"",</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ""from"":""BANGALORE,INDIA"",</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ""startDate"":""30-05-2015"",</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ""timeBetween"":""10:00-12:00"",</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ""to"":""BOSTON,USA""</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; }],</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; ""travelType"":""singlecity""</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">}</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">";</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wtRequest.Body = requestBody;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; yield return wtRequest;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; wtRequest = null;</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva; font-size: medium;">}</span><strong></strong></p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>SQL Server 2012 MDS and SharePoint 2013 Integration</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/sql-server-2012-mds-and-sharepoint-2013-integration</link>
      <pubDate>Thu, 05 Sep 2013 06:15:52 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2013/09/05/sql-server-2012-mds-and-sharepoint-2013-integration/</guid>
      <description><![CDATA[Recently I worked in a demo preparation with my Colleagues who are SQL/BI experts. They were...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: verdana,geneva; font-size: small;">Recently I worked in a demo preparation with my Colleagues who are SQL/BI experts. They were preparing a demo on SQL Server MDS capability. Part of the presentation was to start a workflow within SharePoint if any changes happen in Master Data. They asked me to assist them in this part.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">I started looking into &ldquo;how to&rdquo; part and found the first lesson:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://msdn.microsoft.com/library/gg690195.aspx">http://msdn.microsoft.com/library/gg690195.aspx</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">I found that everything should start working provide you have a SharePoint site and a site workflow in that site in place. Then you just have to mention the Workflow Extender name which is SPWF &ndash; because it is SharePoint and then need to enter the site URL and the Workflow name.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">Great, I created 2 site workflow one using SharePoint Designer and one with Visual Studio. We planned to change some value in Customers and tried to check whether it starts the workflow or not. Essentially we can pass values to the workflow I created using Visual Studio.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">But, it did not work! Then I found an article which claims that we need to create a workflow extender for MDS Workflow Service exclusively</span><br /><span style="font-family: verdana,geneva; font-size: small;">to do so:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://social.msdn.microsoft.com/Forums/sqlserver/en-US/a31769eb-948c-4bb2-844d-72d70e34292b/master-data-services-2012-and-sharepoint-workflow">http://social.msdn.microsoft.com/Forums/sqlserver/en-US/a31769eb-948c-4bb2-844d-72d70e34292b/master-data-services-2012-and-sharepoint-workflow</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">It seems it&rsquo;s only for SQL Server 2012. Previous versions of SQL has that built in. Unfortunately our demo environment was with SQL Server 2012 SP1 and SharePoint 2013 RTM.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">Well, I created the extender, compiled it and tried to implement the same with MDS Workflow Service. But, it started throwing error saying I am using assemblies which are of newer versions than the current environment. What I found was the culprits were &ldquo;Microsoft.SharePoint.dll&rdquo; and &ldquo;Microsoft.SharePoint.WorkfloActions.dll&rdquo;. This is because I am in SharePoint 2013 version and the Workflow Extender in example was in .Net version 3.5. Also it seems MDS wants it that way. Which was ideally using dlls from SP 2010.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">Next thing I did I borrowed the dlls from a SP 2010 server compiled the Extender using them and now the MDS Workflow Service accepted the extender.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">But, again in runtime we started receiving error because the SharePoint dlls are not located in the SharePoint Server (remember we are using SP 2010 dlls but it is a SP 2013 server).</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">So, I was in a catch 22 situation. We have to show a demo in next half a day time where we have a workflow with escalation scenario. Which includes any specific change in customer value will assign a task to a person and then if he does not attend it within 5 mins it will be assigned to the 2<sup>nd </sup>person. Also the task title should include the name of the customer where the data is changed.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">Then I took a drastic step. I created a MDS Workflow Extender and within it I called the Lists.asmx web service of SharePoint and there I added a task to the Workflow Tasks list for the first person. Then I managed the rest of the show by a Site Workflow created using SharePoint Designer. This waits for few mins and then assign the task to the 2<sup>nd </sup>person. Below is the code sample I wrote for the Workflow Extender:</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">using Microsoft.MasterDataServices.WorkflowTypeExtender;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">using System;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">using System.Collections.Generic;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">using System.Linq;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">using System.Text;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">using System.Xml;</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">namespace Services.MDSWorkflowExtender</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">{</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp; public class WorkflowTester : IWorkflowTypeExtender</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #region IWorkflowTypeExtender Members</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void StartWorkflow(string workflowType, System.Xml.XmlElement dataElement)</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Extract the attributes we want out of the element data.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlNode NameNode = dataElement.SelectSingleNode("//ExternalAction/MemberData/Name");</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlNode CodeNode = dataElement.SelectSingleNode("//ExternalAction/MemberData/Code");</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;XmlNode EnteringUserNode = dataElement.SelectSingleNode("//ExternalAction/MemberData/LastChgUserName");</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; try</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; com.contoso.intranet.Lists listService = new com.contoso.intranet.Lists();</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; listService.Credentials = System.Net.CredentialCache.DefaultCredentials;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string strBatch = @"&lt;Method ID='1' Cmd='New'&gt;&lt;Field Name='Title'&gt;Customertype is changed for following customer: " + NameNode.InnerText + "&lt;/Field&gt;&lt;Field Name='AssignedTo'&gt;18;#contoso\\pranab&lt;/Field&gt;&lt;/Method&gt;";</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Guid of the Workflow Tasks list</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string listGuid = "{cc49bc7b-ccde-4bfa-8458-f9bcf7a709d4}";</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //Guid for All tasks view</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string activeItemViewGUID = "{6780F7D4-A0B2-426A-AB86-2C4D8EEFC36A}";</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlDocument xmlDoc = new System.Xml.XmlDocument();</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.Xml.XmlElement elBatch = xmlDoc.CreateElement("Batch");</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elBatch.SetAttribute("OnError", "Continue");</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elBatch.SetAttribute("ViewName", activeItemViewGUID);</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; elBatch.InnerXml = strBatch;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlNode ndReturn = listService.UpdateListItems(listGuid, elBatch);</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catch (Exception)</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw;</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #endregion</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">&nbsp;&nbsp;&nbsp; }</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">}</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">So the learning was if you are using SQL Server 2012, you should use custom Workflow Extender to integrate SharePoint Workflow and use SharePoint 2010 instead of SharePoint 2013 if you don&rsquo;t want sleepless nights.</span></p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Unit Testing JavaScript/JQuery in ASP.Net MVC Project using QUnit Step by Step</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/unit-testing-javascriptjquery-in-asp-net-mvc-project-using-qunit-step-by-step</link>
      <pubDate>Thu, 20 Jun 2013 01:15:00 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2013/06/20/unit-testing-javascriptjquery-in-asp-net-mvc-project-using-qunit-step-by-step/</guid>
      <description><![CDATA[The latest Razor View Model of ASP.Net MVC 3/MVC 4 uses considerable amount of JavaScript/JQuery....]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: verdana,geneva;">The latest Razor View Model of ASP.Net MVC 3/MVC 4 uses considerable amount of JavaScript/JQuery. Sometimes the ActionResult returned by the Controller methods are refined further using JQuery methods before the result in the view. It&rsquo;s very common when we are returning JSON formatted output from the controller method.</span></p>
<p><span style="font-family: verdana,geneva;">We have various options to run the unit test on the .Net code written within controller. But sometimes it&rsquo;s required to test those JavaScript/JQuery codes as well, to check the sanity of the output especially in the situation mentioned above.</span></p>
<p><span style="font-family: verdana,geneva;">QUnit (<a href="http://nuget.org/packages/QUnit-MVC">http://nuget.org/packages/QUnit-MVC</a>, a NuGet package) can help us to run such Unit Test. As per its description:</span></p>
<p><span style="font-family: verdana,geneva;">&ldquo;<em>QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery project to test its code and plugins but is capable of testing any generic JavaScript code (and even capable of testing JavaScript code on the server-side).</em>&rdquo;</span></p>
<p><span style="font-family: verdana,geneva;">Let&rsquo;s see a step by step example of how to use QUnit successfully with ASP.Net MVC project:</span></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 1:</strong> Let&rsquo;s create an ASP.Net MVC 4 Web Application.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8625.11.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8625.11.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8625.11.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8625.11.jpg" alt="" border="0" /></a></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 2:</strong> Choose Internet Application Template. No need to create Unit Test Project.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7633.22.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7633.22.jpg"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7633.22.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7633.22.jpg" alt="" border="0" /></a></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 3:</strong> Once the application created, add following 2 models (Country.cs and City.cs) under &ldquo;Models&rdquo; folder in solution explorer.</span></p>
<p><span style="font-family: verdana,geneva;">using System;</span><br /><span style="font-family: verdana,geneva;">using System.Collections.Generic;</span><br /><span style="font-family: verdana,geneva;">using System.Linq;</span><br /><span style="font-family: verdana,geneva;">using System.Web;</span></p>
<p><span style="font-family: verdana,geneva;">namespace QUnitMvcApp.Models</span><br /><span style="font-family: verdana,geneva;">{</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; public class Country</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string Code { get; set; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string Name { get; set; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static IQueryable&lt;Country&gt; GetCountries()</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new List&lt;Country&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Country</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "AU",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name = "Australia"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new Country</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "UK",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Name = "United Kingdom"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.AsQueryable();</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">}</span><br /><span style="font-family: verdana,geneva;">==========================================================================</span><br /><span style="font-family: verdana,geneva;">using System;</span><br /><span style="font-family: verdana,geneva;">using System.Collections.Generic;</span><br /><span style="font-family: verdana,geneva;">using System.Linq;</span><br /><span style="font-family: verdana,geneva;">using System.Web;</span></p>
<p><span style="font-family: verdana,geneva;">namespace QUnitMvcApp.Models</span><br /><span style="font-family: verdana,geneva;">{</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; public class City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string Code { get; set; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public int CityID { get; set; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public string CityName { get; set; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public static IQueryable&lt;City&gt; GetCitys()</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new List&lt;City&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "AU",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityID=1,&nbsp;&nbsp; </span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityName = "Perth"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "AU",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityID=2,</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityName = "Sydney"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "AU",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityID=3,</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityName = "Melbourne"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "UK",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityID=4,</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityName = "London"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "UK",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityID=5,</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityName = "Bermingham"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; new City</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Code = "UK",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityID=6,</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CityName = "Manchester"</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }.AsQueryable();</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">}</span><br /><span style="font-family: verdana,geneva;">=======================================================================</span></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 4:</strong> Add following few methods to the HomeController.cs file:</span></p>
<p><span style="font-family: verdana,geneva;">public ActionResult CascadingList()</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return View();</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public SelectList GetCountrySelectList()</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var countries = Country.GetCountries();</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return new SelectList(countries.ToArray(),</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Code",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "Name");</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public ActionResult CountryList()</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var countries = Country.GetCountries();</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (HttpContext.Request.IsAjaxRequest())</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Json(GetCountrySelectList(), JsonRequestBehavior.AllowGet);</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return RedirectToAction("CascadingList");</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public ActionResult CityList(string ID)</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; string Code = ID;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var cities = from s in City.GetCitys()</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where s.Code == Code</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select s;</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (HttpContext.Request.IsAjaxRequest())</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Json(new SelectList(</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cities.ToArray(),</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "CityID",</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "CityName")</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; , JsonRequestBehavior.AllowGet);</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return RedirectToAction("CascadingList");</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">Also add following using statement HomeController.cs:</span><br /><span style="font-family: verdana,geneva;">using QUnitMvcApp.Models;</span></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 5:</strong> Add a new view &ldquo;CascadingList.cshtml&rdquo; under View&gt;Homes folder with following code:</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;</span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8875.3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8875.3.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8875.3.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8875.3.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">@{</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; ViewBag.Title = "CascadingList";</span><br /><span style="font-family: verdana,geneva;">}</span><br /><span style="font-family: verdana,geneva;">&nbsp;@{Html.EnableUnobtrusiveJavaScript(true);}</span><br /><span style="font-family: verdana,geneva;">&lt;script type="text/javascript"&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; $(document).ready(function () {</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getCountry();</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; function getCountry() {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CountryList&quot;)/'">'@Url.Content("~/Home/CountryList")/'</a>;</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = "&lt;option&gt;Select a Country&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, country) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (country.Value.indexOf("\'") &gt; -1) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = country.Value + " " + country.Text;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert(s + ": Country.Value cannot contain \'")</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + country.Value + "'&gt;" + country.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CountriesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; function getCity() {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CityList&quot;)/'">'@Url.Content("~/Home/CityList")/'</a> + $('#CountriesID').val();</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = '&lt;option&gt;Select a City&lt;/option&gt;';</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, city) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + city.Value + "'&gt;" + city.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CitiesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span><br />&nbsp;&nbsp;&nbsp; <br /><span style="font-family: verdana,geneva;">&lt;/script&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;h2&gt;Country&lt;/h2&gt;</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">&lt;div id="CountriesDivID"&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;label for="Countries"&gt;Countries&lt;/label&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;select id="CountriesID" name="Countries" onchange="getCity()"&gt;&lt;/select&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;/div&gt;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family: verdana,geneva;">&lt;div id="CitiesDivID" &gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;label for="Cities"&gt;Cities&lt;/label&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;select id="CitiesID" name="Cities"&gt;&lt;/select&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;/div&gt;</span></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 6:</strong> Open up &ldquo;_Layout.cshtml&rdquo; page under Views&gt;Shared folder and add following line under the tab menu section:<br />&lt;li&gt;@Html.ActionLink("CascadingList", "CascadingList", "Home")&lt;/li&gt;<br /></span></p>
<p><span style="font-family: verdana,geneva;">Also add following line under the head tag of the same file:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;script src="@Url.Content("~/Scripts/jquery-1.7.1.min.js")" type="text/javascript"&gt;&lt;/script&gt;</span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8562.4.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8562.4.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8562.4.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8562.4.png" alt="" border="0" /></a></span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;</span></p>
<p><span style="font-family: verdana,geneva;">Now press F5 to debug this application and go to CascadingList tab. You can see our JQuery/JavaScript code is working fine and filling up the drop-down list boxes as expected after receiving JSON formatted output from the controller. </span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/0486.5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/0486.5.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/0486.5.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/0486.5.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">Ok, it&rsquo;s time now to set up some Unit Test on the JavaScript code we used in the CascadingList view.</span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;"><strong>Step 7:</strong> Add a reference of the NuGet package QUnit.</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4048.6.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4048.6.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4048.6.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4048.6.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">Search and install QUnit:</span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6787.7.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6787.7.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6787.7.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6787.7.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;"><strong>Step 8:</strong> Add following 2 lines to _Layout.cshtml</span><br /><span style="font-family: verdana,geneva;">&lt;script src="@Url.Content("~/Scripts/qunit.js")" type="text/javascript"&gt;&lt;/script&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;link href="@Url.Content("~/Content/qunit.css")" rel="stylesheet" type="text/css" /&gt;</span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5430.8.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5430.8.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5430.8.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5430.8.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;"><strong>Step 9:</strong> Now it&rsquo;s time to convert our code into more &ldquo;Unit Testable&rdquo; Format. Instead of calling the getCity() function from the onchange event of the select &ldquo;Country&rdquo;, we will add the code into the OnLoad event handler. Let&rsquo;s look into the changed CascadingList.cshtml file:</span><br /><span style="font-family: verdana,geneva;">@{</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; ViewBag.Title = "Cascading List";</span><br /><span style="font-family: verdana,geneva;">}</span><br /><span style="font-family: verdana,geneva;">&nbsp;@{Html.EnableUnobtrusiveJavaScript(true);}</span><br /><span style="font-family: verdana,geneva;">&lt;script type="text/javascript"&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; var cityCount = 0;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; $(document).ready(function () {</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getCountry();</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CountriesID').change(function () {</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getCity($('#CountriesID').val());</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; function getCountry() {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CountryList&quot;)/'">'@Url.Content("~/Home/CountryList")/'</a>;</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = "&lt;option&gt;Select a Country&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, country) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (country.Value.indexOf("\'") &gt; -1) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = country.Value + " " + country.Text;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert(s + ": Country.Value cannot contain \'")</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + country.Value + "'&gt;" + country.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CountriesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; })</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Removed/////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; @*function getCity() {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CityList&quot;)/'">'@Url.Content("~/Home/CityList")/'</a> + $('#CountriesID').val();</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = '&lt;option&gt;Select a City&lt;/option&gt;';</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, city) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + city.Value + "'&gt;" + city.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CitiesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }*@</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Removed/////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; function getCity(countryId) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CityList&quot;)/'">'@Url.Content("~/Home/CityList")/'</a> + countryId;</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = '&lt;option&gt;Select a City&lt;/option&gt;';</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, city) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + city.Value + "'&gt;" + city.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cityCount++;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CitiesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&lt;/script&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;h2&gt;Country&lt;/h2&gt;</span></p>
<p><span style="font-family: verdana,geneva;">&lt;div id="CountriesDivID"&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;label for="Countries"&gt;Countries&lt;/label&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; @*&lt;select id="CountriesID" name="Countries" onchange="getCity()"&gt;&lt;/select&gt;*@</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;select id="CountriesID" name="Countries"&gt;&lt;/select&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;/div&gt;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family: verdana,geneva;">&lt;div id="CitiesDivID" &gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;label for="Cities"&gt;Cities&lt;/label&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;select id="CitiesID" name="Cities"&gt;&lt;/select&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;/div&gt;</span></p>
<p><span style="font-family: verdana,geneva;">Now press F5 and you will see everything is working as it was before.</span></p>
<p><span style="font-family: verdana,geneva;"><strong>Step 10:</strong> Add code for Unit Testing. This is how the Script block will look like after the change:</span><br /><span style="font-family: verdana,geneva;">&lt;script type="text/javascript"&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; var cityCount = 0;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; $(document).ready(function () {</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getCountry();</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CountriesID').change(function () {</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //getCity($('#CountriesID').val());</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getCity('AU');</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; function getCountry() {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CountryList&quot;)/'">'@Url.Content("~/Home/CountryList")/'</a>;</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = "&lt;option&gt;Select a Country&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, country) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (country.Value.indexOf("\'") &gt; -1) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; s = country.Value + " " + country.Text;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert(s + ": Country.Value cannot contain \'")</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + country.Value + "'&gt;" + country.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CountriesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; })</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Removed/////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; @*function getCity() {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CityList&quot;)/'">'@Url.Content("~/Home/CityList")/'</a> + $('#CountriesID').val();</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = '&lt;option&gt;Select a City&lt;/option&gt;';</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, city) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + city.Value + "'&gt;" + city.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CitiesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }*@</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Removed/////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; function getCity(countryId) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var url = <a href="mailto:'@Url.Content(&quot;~/Home/CityList&quot;)/'">'@Url.Content("~/Home/CityList")/'</a> + countryId;</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.getJSON(url, function (data) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var items = '&lt;option&gt;Select a City&lt;/option&gt;';</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $.each(data, function (i, city) {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; items += "&lt;option value='" + city.Value + "'&gt;" + city.Text + "&lt;/option&gt;";</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cityCount++;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CitiesID').html(items);</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; }</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; /////////////Code Added/////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; ////////////////////Test Code/////////////////////////</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; test("Perform Country onchange", function () {</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $('#CountriesID').trigger("change");</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert("Check No. of cities from Australia");</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; equals(cityCount, 3, "The no. of cities should be 3");</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; });</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; //////////////////////////////////////////////////////</span></p>
<p><span style="font-family: verdana,geneva;">&lt;/script&gt; </span><br /><span style="font-family: verdana,geneva;">And after the last &lt;/div&gt; tag we add:</span><br /><span style="font-family: verdana,geneva;">&lt;div&gt;</span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;h1 id="qunit-header"&gt;QUnit example&lt;/h1&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><br /><span style="font-family: verdana,geneva;">&nbsp;&nbsp;&nbsp; &lt;ol id="qunit-tests"&gt;&lt;/ol&gt;</span><br /><span style="font-family: verdana,geneva;">&lt;/div&gt;</span><br /><span style="font-family: verdana,geneva;">Now press F5 once again, browse to CascadingList and you will see we are actually triggering the onchange event of the Country select box with predefined value to run Unit Test successfully. We have added an alert message just to make sure the effect of onchange gets sufficient time to load.</span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5140.9.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5140.9.png"><img src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5140.9.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5140.9.png" alt="" border="0" /></a></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">So, we have successfully implemented Unit Test on JavaScript written within our ASP.Net MVC application. Happy QUnit-Testing.</span></p>
<p>&nbsp;</p>]]></content:encoded>
    </item>
    <item>
      <title>Tools and Mechanisms available for Unit Test on ASP.Net MVC (Razor) Application</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/tools-and-mechanisms-available-for-unit-test-on-asp-net-mvc-razor-application</link>
      <pubDate>Tue, 26 Feb 2013 00:24:00 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2013/02/26/tools-and-mechanisms-available-for-unit-test-on-asp-net-mvc-razor-application/</guid>
      <description><![CDATA[One of the great things about ASP.Net MVC is easy implementation of Unit Tests. In fact while you...]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: verdana,geneva; font-size: small;">One of the great things about ASP.Net MVC is easy </span><span style="font-family: verdana,geneva; font-size: small;">implementation of Unit Tests. In fact while you start with an ASP.Net MVC </span><span style="font-family: verdana,geneva; font-size: small;">application you get an option to create a Unit Test Project along with the MVC </span><span style="font-family: verdana,geneva; font-size: small;">Project.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">But for a regular ASP.Net developer, ASP.Net MVC </span><span style="font-family: verdana,geneva; font-size: small;">and especially the Razor View Engine (in MVC3/MVC4) sometimes confusing and they </span><span style="font-family: verdana,geneva; font-size: small;">get more confused when they are asked to create Unit Tests on top of it. This </span><span style="font-family: verdana,geneva; font-size: small;">article describes some tools and mechanisms&nbsp;that can&nbsp;help the developers </span><span style="font-family: verdana,geneva; font-size: small;">creating successful Unit Test on their MVC applications.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">1 .Let&rsquo;s first talk about the built in Unit Test </span><span style="font-family: verdana,geneva; font-size: small;">Project Template available within Visual Studio. A good example of how to use </span><span style="font-family: verdana,geneva; font-size: small;">it for MVC can be found here:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://www.asp.net/mvc/tutorials/older-versions/unit-testing/creating-unit-tests-for-asp-net-mvc-applications-cs">http://www.asp.net/mvc/tutorials/older-versions/unit-testing/creating-unit-tests-for-asp-net-mvc-applications-cs</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">It&rsquo;s possible to use this type of Unit Test to </span><span style="font-family: verdana,geneva; font-size: small;">test the output of different controller methods. As given in the example, it </span><span style="font-family: verdana,geneva; font-size: small;">can be the name of the view got returned, Redirect Action or you can even check </span><span style="font-family: verdana,geneva; font-size: small;">the data that is available within the Model associated with the View.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">2. Similar but arguably better option can be </span><span style="font-family: verdana,geneva; font-size: small;">using NuGet&rsquo;s NUnit Template:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://visualstudiogallery.msdn.microsoft.com/7f3bdc82-f418-41aa-ad15-f1d6f89df47a">http://visualstudiogallery.msdn.microsoft.com/7f3bdc82-f418-41aa-ad15-f1d6f89df47a</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">NUnit has a mocking framework built-in. Also it </span><span style="font-family: verdana,geneva; font-size: small;">can run beyond IDE. Which is helpful if you are using a Non-MS Build Server.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">3. In both the above cases, usage of ReSharper (<a href="http://www.jetbrains.com/resharper/download/">http://www.jetbrains.com/resharper/download/</a>) </span><span style="font-family: verdana,geneva; font-size: small;">will give additional advantages.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">4. You can also take advantage of an independent </span><span style="font-family: verdana,geneva; font-size: small;">mocking framework like Moq (<a href="http://code.google.com/p/moq/">http://code.google.com/p/moq/</a>). </span><span style="font-family: verdana,geneva; font-size: small;">Here is one such example: <a href="http://www.codethinked.com/Simplified-Aspnet-MVC-Controller-Testing-with-Moq">http://www.codethinked.com/Simplified-Aspnet-MVC-Controller-Testing-with-Moq</a>.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">5. All the tools we discussed above will give you </span><span style="font-family: verdana,geneva; font-size: small;">options to test methods in Controller classes. Sometimes, you may need to Test </span><span style="font-family: verdana,geneva; font-size: small;">a View or Partial View that is generated as output. NuGet&rsquo;s RazorGenerator can </span><span style="font-family: verdana,geneva; font-size: small;">help you do so. RazorGenerator allows processing Razor files at design time instead of runtime. Here are </span><span style="font-family: verdana,geneva; font-size: small;">the links for RazorGenerator:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://razorgenerator.codeplex.com/">http://razorgenerator.codeplex.com/</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://nuget.org/packages/RazorGenerator.Mvc">http://nuget.org/packages/RazorGenerator.Mvc</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://nuget.org/packages/RazorGenerator.Testing">http://nuget.org/packages/RazorGenerator.Testing</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://blog.davidebbo.com/search/label/RazorGenerator">http://blog.davidebbo.com/search/label/RazorGenerator</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">6. Last but not </span><span style="font-family: verdana,geneva; font-size: small;">the least, QUnit can help you to test the JavaScript and JQuery codes written </span><span style="font-family: verdana,geneva; font-size: small;">within your view files:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://nuget.org/packages/QUnit-MVC">http://nuget.org/packages/QUnit-MVC</a></span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="http://www.dotnetcurry.com/ShowArticle.aspx?ID=400">http://www.dotnetcurry.com/ShowArticle.aspx?ID=400</a></span></p>]]></content:encoded>
    </item>
    <item>
      <title>SharePoint User Migration– AD to ADFS</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/sharepoint-user-migration-ad-to-adfs</link>
      <pubDate>Wed, 27 Jun 2012 06:05:00 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2012/06/27/sharepoint-user-migration-ad-to-adfs/</guid>
      <description><![CDATA[1&nbsp;Introduction
We have a good number of guidance articles and documents on SharePoint 2007 to...]]></description>
      <content:encoded><![CDATA[<h1>1&nbsp;Introduction</h1>
<p><span style="font-family: verdana,geneva;">We have a good number of guidance articles and documents on SharePoint 2007 to SharePoint 2010 migration and also on classic to claim migration for SharePoint 2010 in both Technet and MSDN. But there is no step by step guide to follow if someone wants migrating their existing SharePoint 2007 content with existing users to the cloud and implement ADFS for the same.</span></p>
<p><span style="font-family: verdana,geneva;">Let&rsquo;s consider the following situation &ndash; Fabrikam Inc. already has a Team Portal running on SharePoint 2007 with AD (NTLM) based users. These users also have their individual Mysites and profiles. Contoso Inc. a sister concern of Fabrikam Inc. recently purchased a hosting solution from 3<sup>rd</sup> party where they have options to host SharePoint 2010, SQL 2008 R2 etc. As there are some servers are available to use, Fabrikam Inc. wants to migrate their current SharePoint 2007 content into those servers. They have options to replicate their DC on this cloud environment but due to security risk they would prefer to use ADFS 2.0. They have already set up ADFS 2.0 server locally for this purpose. They also did a pilot migration with a test web application. They successfully transferred the web app from SharePoint 2007 to SharePoint 2010 and also published it into the cloud environment. But later they realized that the users cannot authenticate into the system as SharePoint considers same user coming from AD and from ADFS as two different users. It&rsquo;s also impossible to find out the deep down complex permissions each users has in current environment. So they need a guidance to </span><span style="font-family: verdana,geneva;">achieve this goal.</span></p>
<p><span style="font-family: verdana,geneva;">Let&rsquo;s discuss the entire process in step by step approach.</span></p>
<h1>2&nbsp;Stage 1- from SharePoint 2007 to SharePoint 2010 migration</h1>
<p><span style="font-family: verdana,geneva;">We have extensive guidance document on Technet/MSDN on this. Here is the list of articles including guidance on user profile migration we followed for the demo environment:</span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=3837">http://www.microsoft.com/download/en/details.aspx?displaylang=en&amp;id=3837</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://technet.microsoft.com/library/cc263447(office.14).aspx">http://technet.microsoft.com/library/cc263447(office.14).aspx</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://technet.microsoft.com/en-us/library/cc263299.aspx">http://technet.microsoft.com/en-us/library/cc263299.aspx</a></span></p>
<h2>2.1&nbsp;&nbsp;Implement SSL</h2>
<p><span style="font-family: verdana,geneva;">After migration to SharePoint 2010 we have demo web application running on classic NTLM based authentication. Next, we implemented SSL (required for ADFS) for both the demo web application and the web application for Mysite. We have DNS entries for both these web applications. Here is how the AAM entries look like:</span></p>
<p>&nbsp; <br /> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6862.1.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6862.1.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6862.1.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6862.1.png" /></a></p>
<p>&nbsp;</p>
<h2>2.2&nbsp;&nbsp;Test User Access</h2>
<p><span style="font-family: verdana,geneva;">We checked with random users and found their permission/access, Mysite is running well. Here is one of the permission screens:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4341.2.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4341.2.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4341.2.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4341.2.png" /></a></p>
<p><span style="font-family: verdana,geneva;">And here is a profile view of one of the users:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6735.3.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6735.3.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6735.3.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6735.3.png" /></a></p>
<h1>3&nbsp;&nbsp;Stage 2- AD to ADFS migration On-Premise</h1>
<p><span style="font-family: verdana,geneva;">It&rsquo;s advised to have a content database backup for both the web application at this stage as following steps are irreversible.</span></p>
<p><span style="font-family: verdana,geneva;">As the first step to migrate users from AD to ADFS, we need to transfer both the web application from Classic to Claims. Here are the PowerShell commands used for migration of both the web applications:</span></p>
<p><span style="font-family: verdana,geneva;"><i>$WebAppName = "https://sp.fabrikam.com"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$account = "fabrikam\spadmin"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa = get-SPWebApplication $WebAppName</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>Set-SPwebApplication $wa -AuthenticationProvider (New-SPAuthenticationProvider) -Zone Default</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa = get-SPWebApplication $WebAppName</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$account = (New-SPClaimsPrincipal -identity $account -identitytype 1).ToEncodedString()</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$zp = $wa.ZonePolicies("Default")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$p = $zp.Add($account,"PSPolicy")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$fc=$wa.PolicyRoles.GetSpecialRole("FullControl")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$p.PolicyRoleBindings.Add($fc)</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa.Update()</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa = get-SPWebApplication $WebAppName</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa.MigrateUsers($true)</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>==============================================</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$WebAppName = "https://mysite.fabrikam.com"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$account = "fabrikam\spadmin"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa = get-SPWebApplication $WebAppName</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>Set-SPwebApplication $wa -AuthenticationProvider (New-SPAuthenticationProvider) -Zone Default</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa = get-SPWebApplication $WebAppName</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$account = (New-SPClaimsPrincipal -identity $account -identitytype 1).ToEncodedString()</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$zp = $wa.ZonePolicies("Default")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$p = $zp.Add($account,"PSPolicy")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$fc=$wa.PolicyRoles.GetSpecialRole("FullControl")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$p.PolicyRoleBindings.Add($fc)</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa.Update()</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa = get-SPWebApplication $WebAppName</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$wa.MigrateUsers($true)</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>======================================================</i></span></p>
<p><span style="font-family: verdana,geneva;">After migration you may find users cannot access their individual Mysites. A browser refresh will help after receiving the 401 error screen to log them in.</span></p>
<h2>3.1&nbsp;&nbsp;Introduce ADFS 2.0 as Authentication Provider (Trusted Identity Provider)</h2>
<p><span style="font-family: verdana,geneva;">We implemented ADFS 2.0 to both the web applications. Here is the PowerShell script we used in SharePoint server:</span></p>
<p><span style="font-family: verdana,geneva;"><i>$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\share\fabrikamcert.cer")<br /><br />New-SPTrustedRootAuthority -Name "Token Signing Cert" -Certificate $cert</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;$map = New-SPClaimTypeMapping -IncomingClaimType <a href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress</a> -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;$map2 = New-SPClaimTypeMapping -IncomingClaimType <a href="http://schemas.microsoft.com/ws/2008/06/identity/claims/role">http://schemas.microsoft.com/ws/2008/06/identity/claims/role</a> -IncomingClaimTypeDisplayName "Role" -SameAsIncoming</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$realm = "urn:sp:fabrikam"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$ap = New-SPTrustedIdentityTokenIssuer -Name "Fabrikam ADFS Provider" -Description "SharePoint secured by SAML from Fabrikam" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map,$map2 -SignInUrl <a href="https://fabrikam-adfs.fabrikam.com/adfs/ls">https://fabrikam-adfs.fabrikam.com/adfs/ls</a> -IdentifierClaim "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$uri = new-object System.Uri("https://mysite.fabrikam.com/")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$ap.ProviderRealms.Add($uri, "urn:mysite:fabrikam")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$ap.Update()</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>iisreset</i></span></p>
<p><span style="font-family: verdana,geneva;">As you can see above, we have used email address and role as incoming claim type. This will help us to identify each user and security groups. Also, we need to create two Relying Party Trusts in the ADFS server -o</span><span style="font-family: verdana,geneva;">ne with identifier (&ldquo;urn:sp:fabrikam&rdquo; and "https://sp.fabrikam.com/_trust/") and other with (&ldquo;urn:mysite:fabrikam&rdquo; and <a href="https://mysite.fabrikam.com/_trust/">https://mysite.fabrikam.com/_trust/</a>).<br /><br /><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3073.4.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3073.4.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3073.4.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3073.4.png" /></a></span></p>
<p><span style="font-family: verdana,geneva;">Now we went ahead and add this new identity provider to both the Web Applications.</span></p>
<p>&nbsp;<a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/0218.5.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/0218.5.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/0218.5.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/0218.5.png" /></a></p>
<h2>3.2&nbsp;&nbsp;Migrate users from AD to ADFS</h2>
<p><span style="font-family: verdana,geneva;">Let&rsquo;s add one user and a security group coming from ADFS as members of one of the site collections to check the prefix added by claims. This is required to run the next command in PowerShell.</span></p>
<p><br /> <a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6505.6.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6505.6.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6505.6.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6505.6.png" /></a></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8507.7.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8507.7.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/8507.7.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/8507.7.png" /></a></p>
<p><span style="font-family: verdana,geneva;">Now we deleted both the user and the group created in last step.</span></p>
<p><span style="font-family: verdana,geneva;">We created a ps1 file with following content and run it to change AD users to ADFS users for the demo web application. Make sure you keep at least one of the site collection admin ID from each site collection out of transformation in the code. This is just to keep an option open to login using Normal AD prompt in case something goes wrong:</span></p>
<p><span style="font-family: verdana,geneva;"><i>$groupprefix = "c:0-.t|fabrikam adfs provider|"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$userprefix = "i:05.t|fabrikam adfs provider|"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$usersuffix = "@fabrikam.com"&nbsp; </i></span></p>
<p><span style="font-family: verdana,geneva;"><i># Get all of the users in a web application </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$url = "https://sp.fabrikam.com"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$users = Get-SPUser -web $url </i></span></p>
<p><span style="font-family: verdana,geneva;"><i># Loop through each of the users in the web app </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>foreach($user in $users) </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>{ </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; # Create an array that will be used to split the user name </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; $a=@() </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; $displayname = $user.DisplayName </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; $userlogin = $user.UserLogin </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; $username = &ldquo;&rdquo;</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; if($userlogin.Contains("i:"))<br />#for users</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; { </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $a = $userlogin.split('\') </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $username = $userprefix + $a[1] + $usersuffix</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; } </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;<br />elseif($userlogin.Contains("c:")) #for groups</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; { </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $a = $displayname.split('\') </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $username = $groupprefix + $a[1] </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; }&nbsp;</i><i>&nbsp;&nbsp;&nbsp; </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;<br />if(!$userlogin.Contains("spsitecoladmin1")) #leave one of the site collection admin</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; {</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; #Write-Host $username&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Move-SPUser &ndash;Identity $user &ndash;NewAlias $username -ignoresid -Confirm:$false</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>&nbsp;&nbsp;&nbsp; }</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>}</i></span></p>
<h2>3.3&nbsp;&nbsp;Change User Profile Sync Connections</h2>
<p><span style="font-family: verdana,geneva;">Now we removed the AD connections for User Profile Sync and added a new connection to use ADFS connection:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5481.8.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5481.8.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5481.8.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5481.8.png" /></a><br /><span style="font-family: verdana,geneva;">Also map the user properties correctly:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4682.9.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4682.9.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4682.9.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4682.9.png" /></a><br /><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7853.10.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7853.10.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7853.10.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7853.10.png" /></a></span></p>
<p><span style="font-family: verdana,geneva;">Next we started a full synchronization to get the user profile through. After the sync was over, we tested log-in using one of the user accounts using ADFS login prompt. User movement from demo web application to Mysite is seamless now as ADFS provide us with the WebSSO. Logout is still an issue as logging out from one Web App in the same browser window does not mean logging out from the other. We will discuss about an option to avoid this problem little later.</span></p>
<p>&nbsp;</p>
<h1>4&nbsp;&nbsp;&nbsp;Stage 3- Migration to Cloud</h1>
<p><span style="font-family: verdana,geneva;">Now our web applications are ready to move to cloud. We stopped SQL Server service and copied .mdf and .ldf files for both the web applications&rsquo; content database. We brought those to the SQL Server at Contoso and attached there:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5047.11.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5047.11.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5047.11.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5047.11.png" /></a></p>
<p>&nbsp;</p>
<h2>4.1&nbsp;Setting up the Web Applications</h2>
<p><span style="font-family: verdana,geneva;">We then created 2 web applications with SSL and following AAM (although I used same port 7171 and 8181 for easiness of tracking but that is not mandatory):</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5852.12.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5852.12.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/5852.12.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/5852.12.png" /></a></p>
<p><span style="font-family: verdana,geneva;">Now we mounted the databases to the web applications after testing them:</span></p>
<p><span style="font-family: verdana,geneva;"><i>Test-SPContentDatabase -Name "WSS_Content_7171" -WebApplication "http://appcentral:7171"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>Test-SPContentDatabase -Name "WSS_Content_8181" -WebApplication "http://appcentral:8181"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>Mount-SPContentDatabase -Name "WSS_Content_7171" -DatabaseServer "SQL" -WebApplication "http://appcentral:7171"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>Mount-SPContentDatabase -Name "WSS_Content_8181" -DatabaseServer "SQL" -WebApplication &ldquo;</i><a href="http://appcentral:8181"><i>http://appcentral:8181</i></a><i>&rdquo;</i></span></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">Also enabled Self-Service Site Creation option in the Web application for Mysite (8181) and checked whether managed path &ldquo;/personal&rdquo; is available or not.</span></p>
<p>&nbsp;</p>
<h2>4.2&nbsp;&nbsp;Enabling ADFS</h2>
<p><span style="font-family: verdana,geneva;">We used following command in the SharePoint Management Shell to enable ADFS:</span></p>
<p><span style="font-family: verdana,geneva;"><i>$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2("C:\share\fabrikamcert.cer")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>New-SPTrustedRootAuthority -Name "Token Signing Cert" -Certificate $cert</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$map = New-SPClaimTypeMapping -IncomingClaimType <a href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress">http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress</a> -IncomingClaimTypeDisplayName "EmailAddress" -SameAsIncoming</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$map2 = New-SPClaimTypeMapping -IncomingClaimType <a href="http://schemas.microsoft.com/ws/2008/06/identity/claims/role">http://schemas.microsoft.com/ws/2008/06/identity/claims/role</a> -IncomingClaimTypeDisplayName "Role" -SameAsIncoming</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$realm = "urn:sp:contoso"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$ap = New-SPTrustedIdentityTokenIssuer -Name "Fabrikam ADFS Provider" -Description "SharePoint secured by SAML from Fabrikam" -realm $realm -ImportTrustCertificate $cert -ClaimsMappings $map,$map2 -SignInUrl <a href="https://fabrikam-adfs.fabrikam.com/adfs/ls">https://fabrikam-adfs.fabrikam.com/adfs/ls</a> -IdentifierClaim "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$uri = new-object System.Uri("https://mysite.fabrikam.contoso.com/")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$ap.ProviderRealms.Add($uri, "urn:mysite:contoso")</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>$ap.Update()</i></span></p>
<p><span style="font-family: verdana,geneva;"><i>Iisreset</i></span></p>
<p><span style="font-family: verdana,geneva;">As shown above we used same name for the &ldquo;SPTrustedIdentityTokenIssuer&rdquo; as in step 3.1. Also we have 2 additional Relying Party Trusts at the ADFS server at Fabrikam:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4237.13.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4237.13.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/4237.13.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/4237.13.png" /></a><br /><span style="font-family: verdana,geneva;">&nbsp;Also we added the new Trusted Identity provider for both Web Applications:</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/0184.14.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/0184.14.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/0184.14.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/0184.14.png" /></a></p>
<h2>4.3&nbsp;&nbsp;Finally</h2>
<p><span style="font-family: verdana,geneva;">We then configured the User Profile Sync connection with Fabrikam ADFS server as shown in step 3.3. Now we went ahead and checked user access: </span></p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2538.15.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2538.15.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2538.15.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2538.15.png" /></a></span></p>
<p><span style="font-family: verdana,geneva;"></span>&nbsp;</p>
<p><span style="font-family: verdana,geneva;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7318.16.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7318.16.png"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7318.16.png" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7318.16.png" /></a></span></p>
<p><span style="font-family: verdana,geneva;"></span>&nbsp;</p>
<p><span style="font-family: verdana,geneva;"></span>&nbsp;</p>
<p><span style="font-family: verdana,geneva;">So, we were successful in migration of both the demo web application and the Mysite web application to Cloud environment and we also modified the users to use ADFS based authentication. WebSSO between these two web apps are available due to ADFS. We can additionally implement a Single Sign out option to make sure the users got sign-out from both the Web application simultaneously. There is a codeplex solution for the same. The Visual Studio solution, SingleSignOutModule in the 10SharePoint folder from <a href="http://claimsid.codeplex.com">http://claimsid.codeplex.com</a>, includes a custom HTTP module to deploy to your SharePoint web application that includes this functionality.</span></p>
<p>&nbsp;&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7318.16.png" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7318.16.png"></a>&nbsp;</p>
<h1>5&nbsp;Annexure</h1>
<p><span style="font-family: verdana,geneva;">For the current setup we used SharePoint 2010 with June 2011 CU for both the environment (in Fabrikam servers and in Contoso servers). I used SQL Server 2008 R2 for both the cases.</span></p>
<h2>5.1&nbsp;Credits</h2>
<p><span style="font-family: verdana,geneva;">Took help from following resources:</span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://technet.microsoft.com/en-us/library/gg251985.aspx">http://technet.microsoft.com/en-us/library/gg251985.aspx</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://technet.microsoft.com/en-us/library/ff607729.aspx">http://technet.microsoft.com/en-us/library/ff607729.aspx</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://blog.sharepoint-voodoo.net/?p=68">http://blog.sharepoint-voodoo.net/?p=68</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://technet.microsoft.com/en-us/library/cc263299.aspx">http://technet.microsoft.com/en-us/library/cc263299.aspx</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://msdn.microsoft.com/en-us/library/hh446525.aspx">http://msdn.microsoft.com/en-us/library/hh446525.aspx</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://blogs.technet.com/b/speschka/archive/2010/04/27/how-to-create-multiple-claims-auth-web-apps-in-a-single-sharepoint-2010-farm.aspx">http://blogs.technet.com/b/speschka/archive/2010/04/27/how-to-create-multiple-claims-auth-web-apps-in-a-single-sharepoint-2010-farm.aspx</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://marcvaneijk.wordpress.com/2010/06/12/sharepoint-2010-and-adfs-2-0-the-complete-step-by-step-guide/">http://marcvaneijk.wordpress.com/2010/06/12/sharepoint-2010-and-adfs-2-0-the-complete-step-by-step-guide/</a></span></p>
<p><span style="font-family: verdana,geneva;"><a href="http://blogs.technet.com/b/speschka/archive/2010/07/30/configuring-sharepoint-2010-and-adfs-v2-end-to-end.aspx">http://blogs.technet.com/b/speschka/archive/2010/07/30/configuring-sharepoint-2010-and-adfs-v2-end-to-end.aspx</a></span></p>
<h2>5.2&nbsp;&nbsp;Caveats</h2>
<p><span style="font-family: verdana,geneva;">In step 3.3 when we changed the User Profile Sync connections from AD to ADFS, the images uploaded in the profile for the users disappear. This is because the User Profile data refreshes the content from new connections and old data got deleted. There can be alternatives to get the photos back in the User Profile although I didn&rsquo;t go for it.</span></p>
<p><span style="font-family: verdana,geneva;">Moreover, we&nbsp;may also take backup of the User Profile DBs. This will ensure not losing the data user entered in user profile other than the data received from the AD. Because of the extra time and effort I didn&rsquo;t venture the path.</span></p>]]></content:encoded>
    </item>
    <item>
      <title>Issue with SharePoint Workspace and Outlook calendar delegation</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/issue-with-sharepoint-workspace-and-outlook-calendar-delegation</link>
      <pubDate>Mon, 26 Mar 2012 04:05:00 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2012/03/26/issue-with-sharepoint-workspace-and-outlook-calendar-delegation/</guid>
      <description><![CDATA[Scenario:Let&rsquo;s say we have a user called User-A. User-A delegated his/her calendar to User-B....]]></description>
      <content:encoded><![CDATA[<p><span style="font-family: verdana,geneva; font-size: small;"><b>Scenario:<br /></b></span><br /><span style="font-family: verdana,geneva; font-size: small;">Let&rsquo;s say we have a user called User-A. User-A delegated his/her calendar to User-B. User-B has full authority to accept/decline meeting requests on behalf of User-A. Now, another user User-C sent a SharePoint Workspace Meeting Request to User-A. If User-A accepts/rejects this request by himself/herself, it will reflect in the SharePoint Workspace. But if User-B does the same on User-A&rsquo;s behalf, it does not change the status in the SharePoint Workspace.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">What I found after investigation is:</span></p>
<ul>
<li><span style="font-family: verdana,geneva; font-size: small;">When a SharePoint Workspace Meeting is initiated by a presenter, it creates a meeting workspace site under given URL and adds presenter with &ldquo;Full Control&rdquo; access and attendees with &ldquo;Contribute&rdquo; access.</span></li>
<li><span style="font-family: verdana,geneva; font-size: small;">When an attendee (or a delegate) accepts or decline a SharePoint Workspace meeting from outlook, a web service call to &ldquo;/_vti_bin/meetings.aspx&rdquo; of the Workspace site is initiated from outlook. This call does not routed through Exchange.</span></li>
<li><span style="font-family: verdana,geneva; font-size: small;">When this web service call initiated, outlook sends the credential of the current user to SharePoint. If the user has &ldquo;Contribute&rdquo; access to the SharePoint site, it will successfully update the meeting acceptance.</span></li>
<li><span style="font-family: verdana,geneva; font-size: small;">Essentially a delegate, as he has no access to the SharePoint site cannot change the acceptance status although he has full access to attendee&rsquo;s calendar. </span></li>
</ul>
<p><span style="font-family: verdana,geneva; font-size: small;">Let&rsquo;s look into it step by step:</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">We have used 3 servers (VMs) with latest software for the PoC with following config:</span></p>
<ul>
<li><span style="font-family: verdana,geneva; font-size: small;">Server1: Windows Server 2008 R2, Exchange 2010, Office 2010 </span></li>
<li><span style="font-family: verdana,geneva; font-size: small;">Server 2: Windows Server 2008 R2, SharePoint 2010, Office 2010 </span></li>
<li><span style="font-family: verdana,geneva; font-size: small;">Server 3: Windows Server 2008 R2, SQL 2008 R2, Office 2010</span>&nbsp;</li>
</ul>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step1</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">User (Administrator) starts a SharePoint workspace meeting </span><span style="font-family: verdana,geneva; font-size: small;">and invites User (pranabp).</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;"><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3731.1.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3731.1.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3731.1.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3731.1.jpg" /></a></span><br /> <br /> <br /><span style="font-family: verdana,geneva; font-size: small;">&nbsp; <img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2577.2.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2577.2.jpg" /> </span></p>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step2</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">Once invitation is sent we can go and see the </span><span style="font-family: verdana,geneva; font-size: small;">permissions available in the target meeting workspace site.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6507.3.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6507.3.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/6507.3.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/6507.3.jpg" /></a></p>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step3</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">The user (pranabp) has delegated the calendar to user </span><span style="font-family: verdana,geneva; font-size: small;">(arthuro) and &ldquo;arthuro&rdquo; can accept/decline meeting request on behalf of </span><span style="font-family: verdana,geneva; font-size: small;">&ldquo;pranabp&rdquo;.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2046.4.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2046.4.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2046.4.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2046.4.jpg" /></a></p>
<p><span style="font-family: verdana,geneva; font-size: small;">Let&rsquo;s look at the fiddler trace during the meeting </span><span style="font-family: verdana,geneva; font-size: small;">acceptance of &ldquo;arthuro&rdquo; on behalf of &ldquo;pranabp&rdquo;. As we can see outlook process </span><span style="font-family: verdana,geneva; font-size: small;">is directly calling SharePoint web service. Also the call is failing because of </span><span style="font-family: verdana,geneva; font-size: small;">permission issue.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3162.5.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3162.5.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3162.5.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3162.5.jpg" /></a></p>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step4</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">Also if we see the outcome in the SharePoint </span><span style="font-family: verdana,geneva; font-size: small;">&ldquo;Attendees&rdquo; list, we can see the Response field is not updated.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7360.9.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7360.9.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/7360.9.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/7360.9.jpg" /></a></p>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step5</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">Now let&rsquo;s create another workspace and this time we </span><span style="font-family: verdana,geneva; font-size: small;">will add &ldquo;arthuro&rdquo; as contributor in the workspace site manually once it is </span><span style="font-family: verdana,geneva; font-size: small;">created.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2086.6.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2086.6.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/2086.6.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/2086.6.jpg" /></a></p>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step6</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">We will continue and again accept the meeting from the </span><span style="font-family: verdana,geneva; font-size: small;">calendar of &ldquo;arthuro&rdquo; on behalf of &ldquo;pranabp&rdquo;.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3515.10.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3515.10.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/3515.10.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/3515.10.jpg" /></a></p>
<h3><span style="font-family: verdana,geneva; font-size: small;">Step7</span></h3>
<p><span style="font-family: verdana,geneva; font-size: small;">Let&rsquo;s look at the fiddler trace now. It&rsquo;s a success. </span><span style="font-family: verdana,geneva; font-size: small;">Also the SharePoint &ldquo;Attendee&rdquo; list shows accepted by user &ldquo;pranabp&rdquo;.</span></p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/1732.7.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/1732.7.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/1732.7.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/1732.7.jpg" /></a></p>
<p>&nbsp;</p>
<p><a href="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/1362.8.jpg" original-url="http://blogs.msdn.com/cfs-file.ashx/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/1362.8.jpg"><img border="0" alt="" src="https://msdnshared.blob.core.windows.net/media/MSDNBlogsFS/prod.evol.blogs.msdn.com/CommunityServer.Blogs.Components.WeblogFiles/00/00/00/87/38/1362.8.jpg" original-url="http://blogs.msdn.com/resized-image.ashx/__size/550x0/__key/communityserver-blogs-components-weblogfiles/00-00-00-87-38/1362.8.jpg" /></a></p>
<p>&nbsp;</p>
<p><span style="font-family: verdana,geneva; font-size: small;">So, in the conclusion we can say, we need to have the </span><span style="font-family: verdana,geneva; font-size: small;">delegated users as contributors to the SharePoint Workspace site. As you can </span><span style="font-family: verdana,geneva; font-size: small;">see, it&rsquo;s highly improbable that the user who is inviting other users for a </span><span style="font-family: verdana,geneva; font-size: small;">meeting will have&nbsp;much understating about their calendar delegation.</span></p>
<p><span style="font-family: verdana,geneva; font-size: small;">Well, we do not have any straight-forward solution for </span><span style="font-family: verdana,geneva; font-size: small;">this situation. There can be multiple workarounds - let&rsquo;s hope someone the reader community </span><span style="font-family: verdana,geneva; font-size: small;">of this blog post can point out such an workaround.</span></p>]]></content:encoded>
    </item>
    <item>
      <title>SharePoint 2010: Import User Profile photos from file system</title>
      <link>https://docs.microsoft.com/archive/blogs/pranab/sharepoint-2010-import-user-profile-photos-from-file-system</link>
      <pubDate>Fri, 26 Aug 2011 07:40:00 GMT</pubDate>
      <dc:creator><![CDATA[Pranab-MSFT]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/pranab/2011/08/26/sharepoint-2010-import-user-profile-photos-from-file-system/</guid>
      <description><![CDATA[So, you have successfully deployed User Profile Service and Mysite with SharePoint 2010. Now, the...]]></description>
      <content:encoded><![CDATA[<p>So, you have successfully deployed User Profile Service and Mysite with SharePoint 2010. Now, the question is how to populate the users&rsquo; profile photo.&nbsp;&nbsp;The general expectation around SharePoint 2010 is each user will upload their individual profile photo. Lot of people may disagree, reason - well, a user can upload their pet&rsquo;s photo or favorite holiday location&rsquo;s photo or God knows what.</p>
<p>Your CTO may not approve it. Hence, the second choice, Import User Profile Photos from Active Directory. Here is a good article about it:</p>
<p><a href="http://www.tcscblog.com/2010/11/18/import-user-profile-photos-from-active-directory-into-sharepoint-2010/">http://www.tcscblog.com/2010/11/18/import-user-profile-photos-from-active-directory-into-sharepoint-2010/</a></p>
<p>Wait a little. You got shocking news from the Server Admin team. They do not keep thumbnails (user&rsquo;s photo) in AD. Instead of that, all the users&rsquo; photos (snaps taken during assigning them with an access/identity card) are dumped into a file server. And the references are available in some obscure database.</p>
<p>What to do now? Don&rsquo;t worry we have a solution. Let&rsquo;s discuss it:</p>
<p>Let&rsquo;s say the DB maintains at least 3 fields:</p>
<p>EMP ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User Name&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Photo Name</p>
<p>1001&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; donf&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1001.jpg</p>
<p>1002&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tomg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1002.jpg</p>
<p>First of all create an IIS site and copy all the photos within the root file location of the site so that you can browse the photos like:</p>
<p><a href="http://somecomputername/1001.jpg">http://somecomputername/1001.jpg</a></p>
<p>or may be,</p>
<p><a href="http://somecomputername/photos/1001.jpg">http://somecomputername/photos/1001.jpg</a></p>
<p>Just to avoid conflict give read permission to all users to the physical folder where the photo images are located.</p>
<p>Let&rsquo;s create a csv file out of the DB. The structure of the csv file goes like:</p>
<p>emp_id,domain_user_name</p>
<p><a href="http://somecomputername/1001.jpg">http://somecomputername/1001.jpg</a>,donf</p>
<p><a href="http://somecomputername/1002.jpg">http://somecomputername/1002.jpg</a>,toms</p>
<p>Now create a Powershell script file (PS1) like this:</p>
<p>===============================================================</p>
<p>[void][system.reflection.assembly]::loadwithpartialname("Microsoft.Office.Server.UserProfiles")</p>
<p>$csvFile = "D:\photo.csv"<br /><br />$MySiteUrl = <a href="http://mysite.contoso.com/">http://mysite.contoso.com/</a><br /><br />$site = Get-SPSite $MySiteUrl<br /><br />$context = Get-SPServiceContext $site<br /><br />$profileManager = New-Object Microsoft.Office.Server.UserProfiles.UserProfileManager($context)<br /><br />$csv = import-csv -path $csvFile</p>
<p>foreach ($line in $csv)<br /><br />{</p>
<p>$user_name = "contoso\" + $line.domain_user_name</p>
<p>$up = $profileManager.GetUserProfile($user_name)</p>
<p>if($up)</p>
<p>{</p>
<p>$up["PictureURL"].Value = $line.emp_id</p>
<p>$up.Commit()</p>
<p>write-host $user_name,"---&gt;",$up.DisplayName,"---&gt;",$line.emp_id</p>
<p>$up = $null</p>
<p>}</p>
<p>}</p>
<p>=======================================================================</p>
<p>Run the PS1 file from Powershell.</p>
<p>Now if you go to each user&rsquo;s profile you can see the images are available but if you hover you can see it&rsquo;s coming from the location &ldquo;<a href="http://somecomputername/1001.jpg">http://somecomputername/1001.jpg</a>&rdquo;.</p>
<p>Next step is, give SharePoint a free hand to resize those photos into 3 different sizes. Run this command in Powershell window:</p>
<p>Update-SPProfilePhotoStore -MySiteHostLocation <a href="https://mysite.contoso.com/">https://mysite.contoso.com/</a></p>
<p>Now most of the photos must got copied into User profile DB. If you still see the photo url&rsquo;s pointing to &ldquo;<a href="http://somecomputername/1001.jpg">http://somecomputername/1001.jpg</a>&rdquo;, just go ahead and change your csv and make the emp_id from &ldquo;<a href="http://somecomputername/1001.jpg">http://somecomputername/1001.jpg</a>&rdquo; to the URL where Mysite is storing the photos (just check with any photo which pointing to mysite correctly).</p>
<p>Run the PS1 a few times and &ldquo;Update-SPProfilePhotoStore -MySiteHostLocation <a href="https://mysite.contoso.com/">https://mysite.contoso.com/</a>&rdquo; as well.</p>
<p>This should do the job.</p>
<p>But also update your CTO, this is a temporary solution and saving thumbnail in AD is a better solution any day.</p>]]></content:encoded>
    </item>
  </channel>
</rss>