<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="www.w3.org/2005/Atom" xmlns:sy="purl.org/rss/1.0/modules/syndication/" xmlns:dc="purl.org/dc/elements/1.1/" xmlns:content="purl.org/rss/1.0/modules/content/" xmlns:wfw="wellformedweb.org/CommentAPI/" xmlns:slash="purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Dr. Alp Asutay for Modern Cloud Applications</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/dr_alp_asutay_for_modern_cloud_applications/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/dr_alp_asutay_for_modern_cloud_applications/feed.xml</link>
    <description />
    <lastBuildDate>Wed, 17 Apr 2019 03:47:31 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>TFS’in Özelleştirilmesi</title>
      <link>https://docs.microsoft.com/archive/blogs/dr_alp_asutay_for_modern_cloud_applications/tfsin-ozellestirilmesi</link>
      <pubDate>Thu, 30 Mar 2017 13:32:40 GMT</pubDate>
      <dc:creator><![CDATA[Alp Asutay]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dr_alp_asutay_for_modern_cloud_applications/?p=85</guid>
      <description><![CDATA[PROBLEM TANIMI

 	Code Review Süreci,
TFS 2015’in sunduğu code review süreci, checkout edilen kod...]]></description>
      <content:encoded><![CDATA[<strong>PROBLEM TANIMI</strong>
<ul>
 	<li>Code Review Süreci,
TFS 2015’in sunduğu code review süreci, checkout edilen kod için review request’i istenmesi ve isteğin incelenip cevap vermesi ile tamamlanmaktadır,
Hali hazırda TFS’in sunduğu bu süreç code review yollanıp yollanmadığına ve sonuçlarının olumlu olumsuz olduğuna bakmaksınız checkin yapılmasına izin vermektedir,
Checkin esnasında file’lar lock olduğu için changeset’e ait code review work item üzerinde bulunan dosyaların değişip değişmediği kontrol edilememektedir</li>
 	<li>Auto Review Süreci,
Checkin sırasında Grup/Kişi/Folder/Team Project bazlı bazı kısıtlar istenmektedir, örnek kısıtlar;
i. Forbidden Files,
ii. Forbidden Folders,
iii. Forbidden Extension-Folder,
iv. Allowed Extensions,
Bu kısıtların tanımlanması için TFS’in sistemi yeterli olmamaktadır, aksiyondan girilen herhangi bir proje yetki talebi bir otorite’den geçmeden alınabilmektedir.</li>
 	<li>TFS’in sunduğu Visual Studio ile entegre olabilen client side plugin’lerin kullanımı dağıtımda problem yaşabileceği için tercih edilmemektedir.</li>
 	<li>Çalışacak yapıya ait bazı konfigurasyonel paremetrelerin/yetkilerin tutulacağı bir yapıya ihtiyaç vardır, örnek;
Codereview minimum kaç kişi tarafından onaylanmalı,
Hangi team project’ler için code review süreci işletilmeli,
Grup/Kullanıcı/Team Project/Folder/Yetki bilgileri,</li>
 	<li>Hazırlanacak yapının tek taraftan yönetilebilmesi adına work item policy ve comment policy gibi TFS’in sunduğu custom policy’lerinde yeni yapı üzerinde implemente edilmesi gerekmektedir,</li>
 	<li>Kullanılan branch yapısından dolayı Folder bazlı konfigurasyonlara ihityaç vardır TFS bunu destekleyememektedir. Team Project altındaki farklı development gruplarına ait farklı projeler bulunmaktadır</li>
 	<li>Gated checkinde unit test kontrolü yapılırken, tüm projede unit test kontrolü yapılması yerine sadece değişen dosyalara ait unit testlerin kontrolü yapılması adına, changeset’de bulunan dosyaların adı ve pathine ihtiyaç vardır.</li>
 	<li>Hazılanacak konfigurasyon yönetim veri sisteminin TFS’in default collection’ından farklı bir yerde tutulması gerekmektedir.</li>
</ul>
&nbsp;

<strong>ÇÖZÜMLER</strong>

1) Code Review sürecinin yeniden tasarlanması,
a. Checkin notification evet üzerinde ilgili dosyalara erişilemediği için çalışma gated checkin içerisinde yapıldı,
b. Hali hazırda TFS’in code review süreci üzerine gated checkin sırasında araya girip code review kontrolü yapabilecek bir code activity projesi hazırlandı,
c. Hazırlanan proje içerisinde checkin yapılmak istenen file’lara ait code review bulunmadığına bakılır, code review bulunuyorsa, code review’lara ait response’lar analiz edilir, olumlu response’lara ait sayı tanımlı minimum olumlu response sayısından fazla ise checkin’e izin verilir.
d. Checkin izini sırasında file’lar üzerinde review sonrasında değişiklik olup olmadığına her bir dosyanın hash value’su kontrol edilerek bakılır.

2) Code Review öncesinde, checkin sırasında gated checkin öncesinde, checkin yapılan dosyalar ile alakalı kısıtları konumlandırmak için server side olan checkin notification eventi kullanıldı,
a. Checkin notification eventini içeren bir proje hazırlandı, hazırlanan proje TFS Server üzerinde plugins folder’ina library olarak eklenerek çalıştırılması sağlandı, herhangi bir şekilde client’lara dağıtılmasının önüne geçildi,
b. Kısıtlar implemente edilerek, herhangi bir kısıta uymayan dosyalar checkin sırasında red edilerek kullanıcıya bilgi verildi.
c. Kısıtların tanımlarına ulaşabilmek için bir başka proje daha hazırlandı.

3) Server Side hazırlanan checkin notification projesi ve gated checkin projeleri ile client üzerinde ekstra herhangi bir proje yazılmasına veya dağıtılmasına gerek kalmadı.

4) Konfigurasyon parametrelerinin ve yetkilerin tutulması için bir veri tabanı tasarlandı.

5) TFS’in sunduğu custom policy’ler yeni hazırlanan yapı üzerinde de implemente edildi.

6) Yetkilerin folder bazlı verilmesi sağlandı.

7) Gated checkin sırasında değişen dosyalara ait bilgilerin drop folder’da saklanmasını sağlayacak bir code activity yazıldı, gated checkin projesine dahil edildi.

8) Hazırlanan veri tabanı TFS’in default veritabanından ayrıştırıldı.

&nbsp;

<a></a><strong>Veri Tabanı Tasarımı</strong>

Konfigürasyon parametrelerini saklamak için <strong>TFSConfiguration</strong> tablosu hazırlandı,

Grup ve User’lara ait bilgiler, <strong>CheckinGroups</strong> ve <strong>CheckinUsers</strong> tablolarında tutulmakadır,

Yetkilere ait bilgiler, CheckinPermissionTypes tablosunda bulunmaktadır,

<strong>CheckinUserFolder</strong>,<strong>CheckinUserFolderPermissions</strong>, <strong>CheckinGroupFolder</strong> ve <strong>CheckinGroupFolderPermissions</strong> tabloları ile permissionlar yönetilmektedir.

<a href="https://msdnshared.blob.core.windows.net/media/2017/03/TFS_Specialization.png"><img src="https://msdnshared.blob.core.windows.net/media/2017/03/TFS_Specialization.png" alt="tfs_specialization" width="1263" height="812" class="alignnone wp-image-95 size-full" /></a>

<strong>Solution Tasarımı</strong>

Hazırlanan .NET solution 4 farklı projeden oluşmaktadır.

CodeReviewBuildTemplate projesi ile code activity’ler build sırasında kullanılabilecek hale gelirler,
build sırasında alınması gereken BuildDetails gibi parametreler bu proje içerisinde verilir,

CheckinNotification Projesi ile checkinNotificationEvent yakalanır ve gerekli restrictionlar işletilir,

GatedCheckinReviewPolicy projesinde gatedCheckin’deki code review kontrol süreci işletilir,

PolicyConfiguration projesi ile tüm konfigürasyon bilgileri ve yetkiler veri tabanından alınır.]]></content:encoded>
    </item>
    <item>
      <title>Modern Entity Framework - Row &amp; Column Based Security</title>
      <link>https://docs.microsoft.com/archive/blogs/dr_alp_asutay_for_modern_cloud_applications/modern-entity-framework-row-column-based-security</link>
      <pubDate>Thu, 15 Dec 2016 11:03:39 GMT</pubDate>
      <dc:creator><![CDATA[Alp Asutay]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dr_alp_asutay_for_modern_cloud_applications/?p=26</guid>
      <description><![CDATA[Prepared by L.C Waikiki Team(TAYFUN.ESMER@Lcwaikiki.com) and Dr. Alp...]]></description>
      <content:encoded><![CDATA[<em><strong>Prepared by</strong></em><span> L.C Waikiki Team(TAYFUN.ESMER@Lcwaikiki.com</span><span>) and Dr. Alp Asutay</span>

<strong>1. Introduction</strong>

The last few years have seen the rise of Entity Framework object-relational mapper. While getting more robust and improved with each version compared to previous ones, we have been introduced to interceptors starting with Entity Framework 6. Those interceptors allow us to intervene the queries executed against SQL, the result sets coming back from SQL and even the exceptions related to the executions. If you have decided to learn more about interceptors, you must have come across a few implementations on the internet like logging and soft delete concepts. But what we aim here is much more complex and advanced scenario which is going to serve for our security policies based on rows and columns of a table.

At the end of the day, Row Based Security will enable us to implement restrictions on data row access. For example ensuring that employees can access only the data pertinent to their department, or a group of accountants can access the orders only with less than $10.000 total price. Column Based Security on the other hand, will enable us to implement restrictions on columns. It's the data will be restricted again as Row Based Security, but the target is all data under specified columns.

<strong>2. Solution &amp; Implementation </strong>

We all know that limiting data means filtering it, which is done with the “where” keyword. So basically we will apply predicates to the set of entities when queried, at application tier and independently of developers. There are two interceptor levels for the queries before they go out the gate and get executed in SQL. One is DbCommand Interceptor, which is the SQL level and carries DbCommand object which is the very same object SqlCommand derives from. That is not the field we want to work on by altering the SQL command before it gets executed. The other one is DbCommandTree Interceptor, which reveals itself from its name and makes it possible to work with expression trees and alter them with the help of visitor objects. That’s the path we will take to achieve our goal more elegantly.
So, first things first. We are going to create policy expressions holding the main data which defines the target for security policy to be applied: environment, server, database, table (entity), column, field (property of the entity) and even the values or the source of them. You can see the data model below.

<a href="https://msdnshared.blob.core.windows.net/media/2016/12/EFRowColumnSecurity.png"><img src="https://msdnshared.blob.core.windows.net/media/2016/12/EFRowColumnSecurity-300x180.png" alt="efrowcolumnsecurity" width="392" height="236" class="alignnone wp-image-45" /></a>

By holding the environment information along with the server and database, we can apply different policies for a user on different environments such as test, prod, development etc. <em><strong>DbObject</strong></em> and <em><strong>DbObjectField</strong></em> tables are for the entity and its property. These policy securities can be associated with claims, claim groups and users specifically, and the information for that is held in <em><strong>AuthorizationRef</strong></em> and <em><strong>AuthorizationDefinitionRef</strong></em> fields in <em><strong>PolicySecurity</strong></em> table.
The journey of the code written for the implementation of this solution begins as the user steps in our application, which is the Session_Start event for web applications. There we query all the row and column based security policies associated with the incoming user with all the data needed, transform them into <em><strong>DataPolicyExpression</strong></em> objects and store them in distributed cache which happened to be <em><strong>Redis Cache</strong></em> for us.

<a href="https://msdnshared.blob.core.windows.net/media/2016/12/DataPolicyExpression1.png"><img src="https://msdnshared.blob.core.windows.net/media/2016/12/DataPolicyExpression1-300x249.png" alt="datapolicyexpression" width="300" height="249" class="alignnone size-medium wp-image-65" /></a>

Notice that the <strong>PropertyValueSource </strong>value is static with a value next to it which is "2" at this example. However, the source could be External meaning the data for the expression is going to be pulled from an object which implements the interface (<em><strong>IExternalPolicySecurityService</strong></em>) this solution exposes with a method returning <em><strong>Dictionary&lt;string, string&gt;</strong></em> typed value, holding the key for that external values and the actual values (probably a set of IDs of other tables) how and wherever they are coming from. So in that case instead of a static value, we hold that key name of that external source.

Once the concrete class implementing that interface is found on the web project, the method of it is invoked and all the data is returned for the security policy to be used most likely with IN operator instead of equal (=). That external value source option allows us to define policy with dynamic data which needs to be executed at runtime and involves other tables. Other than these two options, we can store our policies with internal value sources, which refers to endpoints of services. Instead of a concrete class implementing a specific interface, a web service can also be used for the same reason but different technical needs. As in the external value case, that service again will return a <strong><em>Dictionary&lt;string, string&gt;</em></strong> typed value. Again in our case this internal value source working with web services always served us set of IDs of other tables to be used along with the IN operator.

We have two separate interceptors for row based policies and column based policies. These two interceptors are registered and waiting for any query to catch before it is executed in SQL Server. At that point, when the <em><strong>TreeCreated</strong> </em>event is triggered, we pull the data from the cache and see if the executing query holds any matching entity (table). If so, the policy information stored in <em><strong>DataPolicyExpression</strong> </em>object is used to build <strong><em>DbFilterExpression</em> </strong>with dynamic filters, to be attached to the query. Building that expression doesn’t happen for every query hit.

Instead, when it is created for the first time, it’s stored in memory for the later hits for the same entity. That process could have done much earlier, like in the Session_Start event for every single user. But that could depend on the number of policies defined for each user, how complex the policies therefore the expression needs to be build are complex, and of course we cannot know for sure if the user is going to hit that table (entity) in that session at all. So the implementation may be different for some technical and performance purposes but at the end of the day with the help of the interceptors, we can apply new filters or replace the existing ones based on our policies.

<strong>3.    Problems &amp; Solutions</strong>

Of course we had some troubles making our code work during this implementation. Firstly, the order for the interceptors to work mattered in a case where a column which both column and row based policies are applied for. Because the data was replaced with the default value of that type –empty string in our case-instead of the column name, again that default value was used in the where clause which caused the queries to have false conditions all the time. It looked something like this:

<em>SELECT Foo1, Foo2, N’’
FROM tb_Table
WHERE N’’ = ‘UK’</em>

Instead of <em>WHERE Foo3 = ‘UK’</em>, the column name was replaced by the default value which was put there due to a column based security for the user not having rights to see that specific column. We simply solved the problem by registering the interceptors in the right other.

Another problem we faced was the query cache mechanism of Entity Framework. The problem rise when an entity is queried more than once. When a value is set in a filter parameter, that value is cached and reused for the further queries. This happens because the interceptors we use implements <em><strong>IDbCommandTreeInterceptor</strong> </em>and the execution of the <em><strong>TreeCreated</strong> </em>method happens only once for the query commands, being cached after.

Even for a new instance of DbContext won’t make any difference, we’ll be stucked with the cached values for the parameters. This situation might be a problem for almost any kind of interceptor works, unless it is using a hard coded value such as true/false for soft delete purpose implementations. While there are a few different work arounds (using functions that produce queries with constants or using properties of a non-mapped objects and such) for this problem, we decided to go with the <em><strong>IEnumerable&lt;TEntity&gt;</strong></em> collection wich is always remain empty. Entity Framework does not cache queries that involves <em><strong>IEnumerable&lt;T&gt;.Contains&lt;T&gt;(T value)</strong></em> call against an in-memory collection, since the values of the collection are considered volatile. That method (Contains) call can be executed in a wrapped DbSet object or at a point of base repository like object for it so no matter what entity the query comes for, Entity Framework won’t replace it with the cached one.]]></content:encoded>
    </item>
    <item>
      <title>Using Esri in Single Page Application frameworks</title>
      <link>https://docs.microsoft.com/archive/blogs/dr_alp_asutay_for_modern_cloud_applications/using-esri-in-single-page-application-frameworks</link>
      <pubDate>Fri, 01 May 2015 05:50:00 GMT</pubDate>
      <dc:creator><![CDATA[Alp Asutay]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/dr_alp_asutay_for_modern_cloud_applications/2015/05/01/using-esri-in-single-page-application-frameworks/</guid>
      <description><![CDATA[Prepared by MSc. &#304;brahim ULUDA&#286; (ibrahim.uludag@turkcell.com.tr) and Dr. Alp...]]></description>
      <content:encoded><![CDATA[<em><strong>Prepared by</strong></em> MSc. &#304;brahim ULUDA&#286; (<a href="https://blogs.msdn.commailto:ibrahim.uludag@turkcell.com.tr">ibrahim.uludag@turkcell.com.tr</a>) and Dr. Alp Asutay

<strong>Durandal</strong> is a modern cross-device, asynchronous cross-platform client framework written in JavaScript and designed to make Single Page Applications (SPAs) easy to create and maintain. This framework is built on latest technology&nbsp;libraries and web components including <strong>jQuery</strong>, <strong>Knockout</strong> and <strong>RequireJS </strong>as <strong>AMD</strong> <strong>loader</strong>.

<strong>Esri's ArcGIS API</strong> is a geographic information system (GIS) for working with maps and geographic information. It is used for: Creating and Using Maps;<br>Compiling geographic data; analyzing mapped information; sharing and discovering geographic information; using maps and geographic information in a range of applications; and managing geographic information in a database. <strong>ArcGIS API</strong> uses <strong>Dojo</strong> as AMD Loader.

Since they use different AMD loaders, using them together is not trivial. Esri states that the ArcGIS API can be only used with Dojo. Durandal suggests to replace RequireJS with Dojo but it is not desired to change one of the core library of Durandal. There is a workaround to use ArcGIS API in Durandal without replacing RequireJS. But there are some issues of this<br>technique.

<ol>  <li>You cannot use <strong>CDN</strong>. The files <strong>must be placed in the project</strong>.</li>  <li>Some effort and much care is required when going to production</li>  </ol>

The versions of RequireJS and ArcGIS API is important. This technique may not work for older versions. The minimum required version of <strong>RequireJS is 2.1.16, and 3.12 for ArcGIS API</strong>.

Here are the steps:

Download ArcGIS API 3.12 from <a href="https://developers.arcgis.com/en/downloads/">ArcGIS web site</a>.

Extract and copy the files into your project.&nbsp;For example you can place ArGIS file bulk&nbsp;into <em>Scripts </em>folder.

Add ArcGIS css to html page. It can be used either from CDN or local.

<em><strong>&lt;link href="https://blogs.msdn.com//js.arcgis.com/3.12/dijit/themes/claro/claro.css" ... /&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </strong></em><br><em><strong>&lt;link rel="stylesheet" href="https://blogs.msdn.com//js.arcgis.com/3.12/esri/css/esri.css" /&gt;</strong></em>

Configure RequireJS paths for <strong>dojo</strong>,<strong> dijit</strong>, <strong>dojox</strong> and <strong>esri</strong>

<strong>requirejs.config({<br>&nbsp;&nbsp;&nbsp; paths: {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'text': '../Scripts/text',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'durandal': '../Scripts/durandal',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'plugins': '../Scripts/durandal/plugins',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'transitions': '../Scripts/durandal/transitions'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'dojo': '../Scripts/arcgis_js_v312_api/arcgis_js_api/library/3.12/3.12/dojo',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'dijit': '../Scripts/arcgis_js_v312_api/arcgis_js_api/library/3.12/3.12/dijit',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'dojox': '../Scripts/arcgis_js_v312_api/arcgis_js_api/library/3.12/3.12/dojox',<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'esri': '../Scripts/arcgis_js_v312_api/arcgis_js_api/library/3.12/3.12/esri'<br>&nbsp;&nbsp;&nbsp; }<br>});</strong>

For production, Grunt is used. Add the paths as empty in the Gruntfile.js.

<em><strong>var requireConfig = {</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; baseUrl: 'app/',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; paths: {</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "jquery": 'empty:',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "knockout": 'empty:',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'bootstrap': 'empty:',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'text': '../Scripts/text',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'durandal': '../Scripts/durandal',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'plugins': '../Scripts/durandal/plugins',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'transitions': '../Scripts/durandal/transitions',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 'dojo': 'empty:',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "dijit": "empty:",</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "dojox": "empty:",</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "esri": "empty:",</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; catchError: true</strong></em><br><em><strong>};</strong></em>

Remove custom-almond in your main file by adding almondFilter and add to tasks. (Configure src and dest according to your configuration), require.js file will be added later for release mode.

<em><strong>replace: {</strong></em><br><em><strong>&nbsp;&nbsp;almondFilter: {</strong></em><br><em><strong>&nbsp; src: ['build/main.js'],</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;dest: 'build/mainalmondFilter.js',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;replacements: [{</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;from: /var requirejs, require, define;(.|[rn])*define("../Scripts/almond-custom", function(){});/g,</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;to: ''</strong></em><br><em><strong>&nbsp; }]</strong></em><em><strong>}</strong></em><em><strong>},</strong></em>

<em><strong>&nbsp;grunt.registerTask('default', [</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ....</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'durandal:main',</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'replace:almondFilter'</strong></em><br><em><strong>&nbsp;]);</strong></em>

After following these steps, ArcGIS API can be used in Durandal SPA projects. But there are still steps before going to production and it is important to follow below steps for each release. Because ArcGIS API makes approximately 200 HTTP requests and this affects the performance of the application. These requests must be combined into one file.

Generating production from ArcGIS web site causes problems. Because it adds dojo to script. Since RequireJS is used as AMD Loader, they conflict with each other. The production code will be generated manually. The step are as below:

<ol>  <li>Open Fiddler. Navigate to all your map pages and consume every action you have implemented. For example, if you have written onlick event, make sure you trigger it. The reason is to load all AMD modules.</li>  <li>In fiddler, sort by name url. Select all URLs in the ArcGIS folder. Export by File&nbsp;&gt; Export Sessions &gt; Selected Sessions &gt; Raw.</li>  <li>Merge all the content of the exported files into one file. Copy the merged file into project. (e.g. <em><strong>~/Scripts/all-arcgis.js</strong></em>). You can use MergeFileContents.zip for merging.</li>  <li>Make the appropriate change in your cshtml file.</li>  </ol>

&nbsp;

<em><strong>@if (HttpContext.Current.IsDebuggingEnabled)</strong></em><br><em><strong>{</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&lt;script type="text/javascript" src="~/Scripts/require.js" data-main="/App/main"&gt;&lt;/script&gt;</strong></em><br><em><strong>}</strong></em><br><em><strong>else</strong></em><br><em><strong>{</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&lt;script type="text/javascript" src="~/Scripts/require.js"&gt;&lt;/script&gt;</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&lt;script type="text/javascript" src="~/main-built.js"&gt;&lt;/script&gt;</strong></em><br><em><strong>&nbsp;&nbsp;&nbsp;&nbsp;&lt;script type="text/javascript" src="~/Scripts/all-arcgis.js"&gt;&lt;/script&gt;</strong></em><br><em><strong>&nbsp;}</strong></em>

<p>&nbsp;</p>]]></content:encoded>
    </item>
  </channel>
</rss>