Blog Home  Home Feed your aggregator (RSS 2.0)  
Mayur's Blog - Monday, February 13, 2017
 
# Monday, February 13, 2017

Type of "ReportClass" that represents report created using RPT file has several APIs to interact with report parameters. You may use the following collection

DataDefintion.ParameterDefinitions

available within ReportClass to interact with report parameters. Additionally, there is a straight forward way if you are just looking to assign parameter values only. You may use the following method available within the root of ReportClass

SetParameterValue("parameterName", object value)

The important thing here is to supply a proper type of object as value. It is very easy to run into trouble with above method signature.

e.g. If I have a parameter that is for DateTime type, then I may just supply a DateTime value in the above method. However, that should not work and result into Missing Parameter Values exception. It is because the value supplied here should be in the form of an array.

Therefore, you may supply a value object something like the following

var paramVal = new DateTime[] { myDateValue };
SetParameterValue("parameterName", paramVal);

So, in short, be careful while assigning parameter values programmatically. You may want to make sure that the supplied value is in the form of an array even if you are just passing one value.

If you are running into this trouble then this tip might save you some time!

Thanks, a lot for your visit. Happy coding!

Monday, February 13, 2017 6:24:08 PM UTC  #       | 
# Tuesday, January 31, 2017

My host OS is Windows 10 with anniversary update.

My guest OS is also Windows 10 with anniversary update.

I was facing this issue while running virtual machines on VMWare Workstation 12. I guess I had this issue for long but I felt a need to really look into this after Windows 10 anniversary update. My virtual machines were really slow.

Even at this moment I am not sure whether it had anything to do with anniversary update and/or windows 10. However, my task manager activities showed me that Windows Defender was locking some files where I had my virtual hard drives created. The solution was to exclude all the folders where the virtual hard drives were stored. I had stored my virtual hard drives locally on my host machine on a separate SSD drive.

For a good measure I also excluded VMware folder available in C drive to make sure that Windows Defender let VMware executable and other components run without blocking.

I am not sure why Windows Defender looked at them skeptically but it was clear that there were being constantly looked by Windows Defender. I guess .VHD files are being updated very frequently by VMWare Workstation when an associated VM is in use. Windows Defender might be tracking them constantly as they were being updated very frequently. That should result into files being locked and unlocked. This might prevent VMWare to work efficiently.

Well... whatever be the reason; I was able to run my VMs efficient after the above change. Now I can run simultaneously 6 instances of Visual Studios, one instance of SQL Management Studio, an Outlook client, a few instances of Edge, a TypeScript compiler and a Node engine with only 4 GB of ram and 2 processors. I had put in 10 GB of RAM and 8 processors earlier and was still running into the issues. Now it looks like that I could utilize the full power of Windows 10 and a 64 bit machine.

I hope that this solution might help to someone who is facing the similar issues related with Windows Defender.

Thanks a lot for visiting my blog. Wishing you a happy virtualization!

Tuesday, January 31, 2017 7:47:00 PM UTC  #       | 

Recently my online organization was upgraded to Dynamics 365 from CRM Dynamics 2016. Everything worked very well except the integration piece that used CRM SDK. The connection component threw an error message shown below.

Error details: Metadata contains a reference that cannot be resolved

The solution was to upgrade the DLL components to newer SDK components. My integration project was still using an SDK for CRM Dynamics 2016. It was quite obvious that the SDK needed an upgrade as well.

I could have downloaded the SDK using the following site. 

Please note that choosing an option of MicrosoftDynamics365SDK.exe is important. The other option is for CRM2016 version. 

https://msdn.microsoft.com/dynamics/crm/downloads

However, I prefer NuGet packages. I searched NuGate by "crmsdk" and chose "Microsoft Dynamics 365 Core Assemblies". As I was using integration to interact with entities and run some CRUD operations on them, I really did not need any other package. This package had required components to connect to CRM instance and to create ServiceProxy for the CRMContext. NuGate was able to download and reference the following DLLs.

Microsoft.Crm.Sdk.Proxy, Microsoft.Xrm.Sdk and Microsoft.IdentityModel

Once I upgraded to newer version everything was good except an instance of CrmConnection type. I noticed that the new SDK was missing this type. So, I quickly added my own implementation as shown below.

public class CrmConnection
    {
        public Uri ServiceUri { get; private set; }
        public string UserName { get; private set; }
        public string Password { get; private set; }
        public ClientCredentials ClientCredentials {get; private set;}

        /// <summary>
        /// Parses a connection string and returns a new instance of CrmConnection
        /// <para>
        /// Connection string format: Url=https://orgname.api.crm.dynamics.com/xrmservices/2011/organization.svc;Username=abc@orgname.onmicrosoft.com;Password=def;
        /// </para>
        /// </summary>
        /// <param name="connectionString"></param>
        /// <returns></returns>
        public static CrmConnection Parse(string connectionString)
        {
            if (string.IsNullOrWhiteSpace(connectionString))
            {
                throw new Exception("Connection string was not suppled!");
            }

            var connectionElements = connectionString.Split(';');

            if (connectionElements.Length < 3)
            {
                throw new Exception("Invalid connection string!");
            }

            var crmConnection = new CrmConnection();
            
            crmConnection.ServiceUri = new Uri(ParseServiceUrl(connectionElements));
            crmConnection.UserName = ParseUserName(connectionElements);
            crmConnection.Password = ParsePassword(connectionElements);
            crmConnection.ClientCredentials = GetAuthenticationCredentials(crmConnection.UserName, crmConnection.Password);

            return crmConnection;
        }

        private static string ParseServiceUrl(string[] connectionElements)
        {
            var urlElement = connectionElements[0].Split('=');
            return urlElement[1];
        }

        private static string ParseUserName(string[] connectionElements)
        {
            var urlElement = connectionElements[1].Split('=');
            return urlElement[1];
        }

        private static string ParsePassword(string[] connectionElements)
        {
            var urlElement = connectionElements[2].Split('=');
            return urlElement[1];
        }

        private static ClientCredentials GetAuthenticationCredentials(string userName, string password)
        {
            var credentials = new ClientCredentials();
            credentials.UserName.UserName = userName;
            credentials.UserName.Password = password;
            return credentials;
        }
    }

This change only needed to build my integration project. I was able to use my existing code with this fix.

I am writing this post and hope that this may be useful to someone facing the similar issues and looking for a quick help.

Thanks a lot for vising my blog!

Tuesday, January 31, 2017 5:46:05 PM UTC  #       | 
# Thursday, October 20, 2016

Are you experiencing the same what I have just experienced? I wanted to register a device using Push.RegisterAsync(string regiId, JObject templates) with tags. I could not find any explanation on the signature of templates object required as one of the parameters of this method.

When I looked into GitHub to check the source to figure out the issue, I was able to locate the correct format of this templates object.

push.RegisterAsync(.., ..) method eventually calls the following controller

https://github.com/Azure/azure-mobile-apps-net-server/blob/master/src/Microsoft.Azure.Mobile.Server.Notifications/Controllers/NotificationInstallationsController.cs

This controller has two parameters. One of them is an object of the following class

https://github.com/Azure/azure-mobile-apps-net-server/blob/master/src/Microsoft.Azure.Mobile.Server.Notifications/NotificationInstallation.cs

So, to provide tags correctly, a client must provide a valid instance of NotificationInstallation. You may want to use the public property named "Tags" here and provide a list of tags. However, this would still not work because of the following bug. I have created this issue within project Microsoft.Azure.Mobile.Server.Notifications on GitHub. I am yet to hear something from the project moderator or members. So I don't know whether what I have proposed is correct or not.

Azure/azure-mobile-apps-net-server#162

However, I needed to complete my work so I implemented my own version of NotificationInstallationsController to fix the issue. It works for me indeed. So I think that what I have proposed should be correct.

I am adding this explanation here, in case, if some one is having the same problem and looking for any solution, then this would help. If you need further information, please let me know.

Thursday, October 20, 2016 6:42:56 PM UTC  #       | 
# Sunday, September 18, 2016

We have seen many web applications with multiple pages. In fact, before the advent of the SPA, muti-page applications were only existed. In reality, there are many muti-page applications in development in today's date as well. Especially, when the application is huge and when it servers many different domains and purposes, the designer could decide in favor of doing muti-page application instead of SPA. When a web application is huge, it is also likely that each page within this multi-page application serves a purpose of SPA. This kind of set up gives the best of both the worlds. By doing multi-page application we do not allow a particular page to grow a lot. That improves maintainability. Additionally, if different pages serves totally different business purposes, then it is a good idea to keep them separate to maintain "separation of concern".

Implementing client side development with Angular2 for any muti-page application requires a little different set up. You may not be able to strictly follow the samples available on Angular2 site. Many of those samples are designed for the SPA.

I came across a situation where I needed to implement Angular2 with muti-page web application. I followed the approach as outlined here. I thought to share the same idea here. I hope that this may be helpful to someone else in need of doing the same thing.

Additionally, you may have an older application that is also a multipage application. Here you may be looking forward to implement the client side development using Angular2. In this case you don't have a choice unless you may want to re-write an application to be an SPA. Re-writing is not always possible. So in this case as well the following discussion might be useful.

Here I explain how to set up Angular2 and how to configure SystemJS to use Angular2 for a multi-page client side web application development. I am using Asp.NET MVC Core as my server side development platform. However, we are discussing here about client side development and this discussion is valid for any server side platform/technology.

1) Create app-components folder under wwwroot

2) Add required components for your application here. For example, if there is a page to manage employees, then you may create employee-edit component here

3) You may create another folder within app-components called common-services

4) You may want to add database services here. For example, you may add employee service to retrieve and update employees

5) You may create another folder within common-service named domains

6) You may use this folder to create interfaces used across your Angular2 project. For example, you may use IEmployee so that data retrieved from employee service can be passed across components by casting JSON to IEmployee. The same way data collected from UI using components can be passed to employee service via IEmployee to make any update in the database

Above image 1: Folder structure

Above image 2: How to refer required services, components and domains within a component

Above image 3: Setting up a service

7) In addition to this you may also see common-components in the screen capture created to show folder structure. This folder actually holds components common to other components. For example, there is component to show error messages. This component is being shared across other components. Such type of common components created for re-usability can be stored here.

Above image 4: Common components

8) There is also another folder called common. It holds common objects but not necessarily domains. For example, Enum.

The logic behind this kind of folder structure is to follow the dependency order. For example, components depend on services, services depend on domains etc. By following this folder structure it is easy to refer the items using import statement. Please refer image 1 to see how consistent it becomes to refer a dependency by following this structure.

9) The next important aspect is to set up bootstrappers and module. As our application is muti-page application we need to set up boot-strapper and module for each page. For example, my application has employee management page. I will set up boot-strapper and module as shown below. You may create modules and page-bootstrappers folder under wwwroot

Above image 5: Module and Boot-strapper

Above image 6: How to refer various dependencies in a module

Above image 7: How to refer module in a boot-strapper

10) Now it is time to set up SystemJS configuration as shown below

(function (global) {
    var packages = {
        'rxjs': {
            defaultExtension: 'js'
        },

        'page-bootstrappers/employee': {
            defaultExtension: 'js',
            main: 'employee-management.js'            
        },
        'page-bootstrappers/admin': {
            defaultExtension: 'js',
            main: 'admin-employee-management.js'
        }
    };

    System.defaultJSExtensions = true;

    System.config({
        baseURL: location.protocol + '//' + location.host,
        paths: {
            'npm:':'node_modules/'
        },
        map: {
            //angular bundles
            '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
            '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
            '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
            '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
            '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
            '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
            '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
            '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
            
            //other libraries
            'rxjs': 'npm:rxjs',

            //my application
            '../app-components/': 'app-components/'
        },
        packages: packages        
    });

})(this);

 

11) Please note:

As this is a multi page, SystemJS must be configured to use baseURL as shown above. Our folder structure for Angular2 always assumes a request from the root to load any component.

12) The following shows the employee management cshtml in VIEWS folder

Above image 8: Employee management folder which users Angular2

The following shows how we set up Employee management page to use Angular2

@{
    ViewBag.Title = "Employee Management";
    Layout = "~/Views/Shared/_LayoutBootstrap.cshtml";
}

<script src="/js/shim.min.js"></script>
<script src="/js/zone.js"></script>
<script src="/js/Reflect.js"></script>
<script src="/js/system.src.js"></script>
<script src="/systemjs.config.js"></script>
<script src="/js/ej.angular2.min.js"></script>
<script>
    System.import('page-bootstrappers/employee').then(function () { }, console.error.bind(console));
</script>
<section>
    <employee-profile>
        <span class="fa fa-spinner fa-pulse fa-3x"></span>&nbsp;&nbsp;&nbsp; Please wait... loading web components and data
    </employee-profile>
</section>

Please note required java script libraries. "js/ej.angular2.min.js" is a third party component library offered by Syncfusion. You may not need it or you may replace it with whatever third party components you are using.

I have created this article based on Angular2 - version 2.0.0. At the time of writing this article, this was the latest version. In the future, this set up may change as per changes applied to Angurlar2 framework.

I hope that this may be useful. If you have any other suggestion to improve it, then please let me know.

Thank you and happy coding!

Sunday, September 18, 2016 7:12:51 PM UTC  #       | 
# Wednesday, July 13, 2016

Asp.Net MVC Core 1.0 can be configured to read from environment variable. This is useful especially when you have different machines for different environments such as production, stating and development. However, this set up does not work when you have one machine for different environments. For smaller businesses one machine may host both production and staging environment. For a small team of developers working on a prototype there may be only one machine for different environments to save on cost.

In this situation, configuration based on environment variable may not work. Here I will show how you can configure the project to utilize solution configuration (similar to older Asp.NET MVC where we have used various configuration files such as web.debug.config, web.release.config etc.)

1) Add configuration name and compile symbols

As shown below add required configurations in project.json. For each configuration we need to define a compilation symbol 

Image 1

2) Startup.cs

Add the following highlighted code in Startup method of Startup.cs file. As shown here we are using compilation directives to update the type of environment programmatically.

Image 2

Similar to older Asp.Net MVC, here you need to change the configuration (as shown below) before you build or publish the application.

Image 3

Depending on what solution configuration you are building, the compiler directive would emit the required code. This way the code in Starup method will be modified during compile time.

Please look into image 2 once again and notice how we are adding JSON configuration file.

3) appsettings.json

As shown below add required appsettings.json files. Please note the naming of the files. It should match the names specified in Startup method (see image 2) while creating the builder object.

Image 4

4) Build and Test

Build your project and test it. Try publishing your project with different solution configuration and test whether the set up is really working.

5) Side notes for post-compile and pre-compile

If you ever need to run some scripts before or after compilation based on configuration, then you may utilize the following "precompile" (or "postcompile" not shown) directive available within project.json. As shown below I am running a batch file where I am passing a name of solution configuration selected. Please pay attention to %compile.Configuration%. That's how I request MsBuild to provide the name of solution configuration. That value is transferred to a batch file as a parameter.

This batch file can be used for anything. It may copy several files depending on what is being built. In my case I have app.config (shown in Image 6) file where I have database connection string. You may notice that I am using configsource. So now I need to generate connectionstrings.config and copy it to the same level where app.config is available. By this time you might have figured out that I am going to three connectoionString.config file responsible to carry connection strings for my three different solution configurations. Again this is the same approach we followed during traditional .NET development.

(Generally we specify database connection string in appseetings.json. However, I have a few legacy class libraries. It was going to take a lot to refactor them to inject configuration service as suggested in Asp.NET MVC Cor 1.0. So I was left with no option but to add connection string to app.config. This way class libraries can be provided with database connection during runtime. At this point I am not debating on what is right or wrong but the whole point here is to demonstrate how you can utilize the build processes with ASp.NeT MVC Core 1.0 and leverage what you have been doing with an older Asp.Net MVC set up so far)

Image 5

Image 6

As shown in the following image, I have various connectionstring.config file for various solution configurations. The file precompilescript.bat is the file where I have a logic to find required connectionstrings.<%compile.configuration%>.config and copy that as connectionStrings.config. This all happens during pre-build. That means a correct file is copied just before a build begins. During run time app.config references it and provides a correct connection string.

Image 7

Image 8

Asp.NET MVC Core  1.0 is quite new. The way it has been set up is very different than the traditional .NET development. It is likely that we will have to mix and match a traditional approach with a new approach for the next few years until everything we need to build a web application get transferred to this newer approach.

I hope the above mentioned work around may help.

I am also new to this kind of development approach. If you feel that you have better suggestion in context with this blog post, then please feel free to let me know. I really appreciate any opportunity to learn something new and better.

Thanks a lot for reading. Have fun with coding!!

Wednesday, July 13, 2016 9:52:08 PM UTC  #       | 
# Thursday, June 16, 2016

Today I had to use a development machine running under VMWare workstation. I was doing mobile app development for Android. When I launched the debug mode the emulator all of a sudden failed to launch. I received the following error message.

"The Virtual Machine Management Service failed to start the virtual machine 'Emulator.' because one of the Hyper-V components is not running (Virtual machine ID BZCC6546-129T-4683-922F-52EAT972E888)"

This message indicates that the hyper-v was not able to launch the virtual machine. The problem is caused by the way hyper-v creates a virtualization of a virtual processor. Since I was running a virtual machine, the hyper-v tried to create the virtualization of a virtual processor. Obviously  it failed because the virtual processor did not support virtualization of itself. Fortunately, I was running under VMWare workstation 12 as well as the actual physical machine also supported the virtualization set up provided by VMWare.

So I shut down the VM and went to the settings and enabled the following option under processors. That solved the problem. Hyper-v was able to properly run the emulator.

Hopefully this hint may help someone facing the similar problem.

Thursday, June 16, 2016 7:14:14 AM UTC  #       | 
# Sunday, April 10, 2016

There are many useful posts available to resolve this issue. This issue arises due to race condition. It is important that ASYC methods are written carefully. Care should be taken so that all the references within ASYC method should not return VOID but at least a TASK.

I came across a scenario where a method responsible to execute database and smtp operations was running into this problem. As shown below the database operations were using ASYC methods, however, SMTP was a non-async method. It was a VOID method with no return

Database operations were running into AsyncLock to make sure that it is thread safe. Thread safety was needed as unique identifier of a company record was generated by the code.

After database operations are successful, ProcessRegistration calls a method to run an smtp operation. As it is not an ASYC method and does not return, ProcessNewRegistration Task can declare itself completed. However, smtp operation may not be complete as emailing sometimes not quicker depending on how many emails in the queue of SMTP Server. In this case, when the thread running ProcessNewRegistration Task tries to complete the task, it runs into a problem. This is due to pending task of smtp operation might be still not complete.

The resolution of this problem is to have SendRegistrationEmail as ASYNC too. This allows to await this method. Doing this forces the thread to wait before issuing a token to complete ProcessNewRegistration task. 

If you are running such problems, a good examination of the code base is needed. Refactoring may be needed. The rule of thumb is never use VOID methods.

public async Task<Company> ProcessNewRegistration(Company company, decimal registrationCost, string paymentId)
        {
            var login = await loginRepositoryService.GenerateNewLogin(Interfaces.Enum.UserRole.ClientAdmin);
            company = await GenerateCompany(company, login);
            SendRegistrationEmail(company.CompanyCode, company.Contact1Name, company.Contact1Email, registrationCost, paymentId);
            return company;
        }
private void SendRegistrationEmail(string companyCode, string name, string email, decimal amount, string paymentId)
        {
            var body = $@"<strong>Hi {name}</strong>
                        <p>Thank you very much for your registration.</p>
                        <p>Please accept this email as your reciept of payment.</p>
                        <p>Registration details</p>
                        <strong>Company code: </strong>{companyCode}<br />
                        <strong>Amount paid: </strong>${amount}<br />
                        <strong>Pyament id: </strong>${paymentId}<br />
                        <strong>Date of payment: </strong>{DateTime.Now.ToString("yyyy-MM-dd")}<br />
                        <p>We appreciate your business and looking forward to exceed your expectations.</p>
                        <p>&nbsp;</p>
                        <strong>Sincerely,</strong><br />
                        Customer Service Team
                        ";
            UtilityService.SendEmail(email, "admin@mail.ca", "Confirmation: Registration and Payment", "admin@mail.ca", string.Empty, body, null, null);           
        }
 
private async Task<Company> GenerateCompany(Company company, Login login)
        {            
            using (var al = await asyncLocker.LockAsync())
            {
                var latestCompanyId = await companyService.MaxAsync(c => c.CompanyId);
                var latestCompany = await companyService.FindAsync(latestCompanyId);
                var code = 0;
                if (!int.TryParse(latestCompany.CompanyCode, out code))
                {
                    throw new Exception("Error while generating company code");
                }
                company.CompanyCode = (++code).ToString();
                company.Logins.Add(login);
                companyService.Add(company);
                var id = await companyService.FlushChanges(company);                
            }

            return company;            
        }

Corrected methods to run smtp operations.

public async Task<Company> ProcessNewRegistration(Company company, decimal registrationCost, string paymentId)
        {
            var login = await loginRepositoryService.GenerateNewLogin(Interfaces.Enum.UserRole.ClientAdmin);
            company = await GenerateCompany(company, login);
            await SendRegistrationEmail(company.CompanyCode, company.Contact1Name, company.Contact1Email, registrationCost, paymentId);
            return company;
        }
private async Task SendRegistrationEmail(string companyCode, string name, string email, decimal amount, string paymentId)
        {
            var body = $@"<strong>Hi {name}</strong>
                        <p>Thank you very much for your registration.</p>
                        <p>Please accept this email as your reciept of payment.</p>
                        <p>Registration details</p>
                        <strong>Company code: </strong>{companyCode}<br />
                        <strong>Amount paid: </strong>${amount}<br />
                        <strong>Pyament id: </strong>${paymentId}<br />
                        <strong>Date of payment: </strong>{DateTime.Now.ToString("yyyy-MM-dd")}<br />
                        <p>We appreciate your business and looking forward to exceed your expectations.</p>
                        <p>&nbsp;</p>
                        <strong>Sincerely,</strong><br />
                        Customer Service Team
                        ";
            await UtilityService.SendEmail(email, "admin@mail.ca", "Confirmation: Registration and Payment", "admin@mail.ca", string.Empty, body, null, null);           
        }
 
Sunday, April 10, 2016 11:48:03 PM UTC  #       | 
# Tuesday, December 29, 2015

Sometimes things are straight forward but easy to miss. If you are implementing a client to consume RESTful APIs and like to leverage RestSharp library, then the configuration is pretty straight forward to utilize windows authentication.

RestSharp provides "RestRequest" class. An object of "RestRequest" can be instantiated with required values such as API address and type of method (i.e. post or get or put etc.). This object can be used to enable windows authentication as shown below.

var request = new RestRequest(resource, Method.POST);
request.UseDefaultCredentials = true;

Here "UseDefaultCredentials" is set to "true" to enable windows authentication.

This is great; easy and simple. However, this would be repeating the configuration to enable windows authentication each time a new request is created. To fix this problem I would like propose an alternative. RestSharp also provides another class "RestClient". This class is actually an equivalent to "WebClient" in .NET. It exposes a few useful properties such as a base URL for the API and Authenticator. Authenticator is "IAuthenticator" type. Authenticator can be used to configure the authentication mechanism for the client. So we can implement our own Authenticator as shown below to specify windows authentication.

internal class WinAuthenticator : IAuthenticator
    {
        public void Authenticate(IRestClient client, IRestRequest request)
        {
            request.UseDefaultCredentials = true;
        }
    }

Once this is done we can make a request to an API with custom authenticator as shown below.

var client = new RestClient("BaseApiConnection");
client.Authenticator = new WinAuthenticator();
            
With the help of this client we can create a request as shown below
var request = new RestRequest(resource, Method.POST);
            IRestResponse response = null;
            request.AddJsonBody(data);
            response = client.Execute(request);
This way a single client can be shared across all the requests.
Tuesday, December 29, 2015 7:16:30 PM UTC  #       | 
# Tuesday, October 27, 2015

Earlier there were posts regarding how to build AMD modules with RequierJS and MS Build. Changes were needed to MS Build because there was no direct support from Visual Studio. The MS Build triggered NodeJS to complete the build process and copied required files to the output directory or deployment folder.  

However, Asp.Net MVC vNext (6 or later) web template with Visual Studio 2015 supports client side building tools such Grunt and Bower. Therefore, the client side building has become simpler and does not require a customization to MS Build. But what if you have Asp.Net MVC with version 4 or 5. Older version of MVC templates do not come with support of Bower and Grunt to build required JavaScript. Therefore, you are still stuck with MS Build customization even though you have Visual Studio 2015.

Here I will show one of my experiments where I have implemented client side building of JavaScript. I wanted to build RequireJS AMD modules for multi page Asp.Net MVC 5 using Bower and Grunt.

Again please note that my implementation is based on Visual Studio 2015 but I am using Asp.Net MVC version 5. If you are using vNext then everything is built-in. However, at the time of writing this post the vNext was till in Beta and was not everyone's choice of production development. This approach may not be 100% perfect, however, I believe and hope that it could be a good guiding block to whomsoever wants to implemented a client side build environment for the JavaScript.

Why do we need client side build?

Most of client side libraries are written in JavaScritps and maintained in open source environments. These environments may not necessarily compatible with .NET and Visual Studio. As typical .NET developers we are used to with NuGet packages where we maintain .NET based packages. JavaScritp based packages are available in NuGet too but they are just an extension of the original open source packages. Someone has to volunteer to build NuGet packages. Therefore, it is possible that these packages may not be up to date. Wouldn't it be nicer if we could directly interact with those packages directly instead of getting them through NuGet?

Additionally, good practices such as AMD (asynchronous module) requires modules to be created and served in a certain a way. That includes concatenation of certain modules, minification and cleaning of the modules etc. Essentially it is similar to gathering certain C# files available in a project and creating a DLL by putting them altogether. Moreover, it should not minify when it is in debug/development mode but do it when it is a time for a deployment.

JavaScript development has gathered so much important due to its wide spread usage. Therefore, now days, client side development has taken off a lot. Probably the developers now writing as much JavaScript as much of the managed codes at the server side. Therefore, we need something so that we can manage and maintain client side development.

-- My apology for leaving the post incomplete; something has to be tacked on a priority; I will be back to complete the post as soon as possible; please come again after a few days to read the completed post; thank you -- 

 

Tuesday, October 27, 2015 12:26:36 AM UTC  #       | 
Copyright © 2020 Mayur Bharodia. All rights reserved.
DasBlog 'Portal' theme by Johnny Hughes.
Pick a theme: