Category: .NET

.TT – add more informations(.NET version , build ) – part 6 of 7

As you can see from the previous chapter, we have added to the AssemblyDescription more informations – like .NET version, build configuration , and more

You can see those with an explorer add-on http://www.codeproject.com/Articles/118909/Windows-7-File-properties-Version-Tab-Shell-Extens

Video : http://youtu.be/A_qSdVV93qk

Demo project here : https://traceabilitydemo.codeplex.com/releases/view/132231

Source code here : https://traceabilitydemo.codeplex.com/SourceControl/changeset/view/110446

Traceability in .NET–.tt files–add changeset – part 5 of 7

We wish to add , from the .tt file , the id of the last TFS checkin. For this purpose we will connect to TFS and we will investigate in the current project the latest change.

We will use the facility of .tt file to connect to the host and ask for various features ( such as TFS )

The .tt file code is:

  

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="Microsoft.VisualStudio.Shell.Interop.8.0" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="EnvDTE80" #>


<#@ assembly name="Microsoft.VisualStudio.TeamFoundation.VersionControl" #>
<#@ assembly name="Microsoft.TeamFoundation.Client"#>
<#@ assembly name="Microsoft.TeamFoundation.Common"#>
<#@ assembly name="Microsoft.TeamFoundation"#>
<#@ assembly name="Microsoft.TeamFoundation.WorkItemTracking.Client"#>
<#@ assembly name="Microsoft.TeamFoundation.VersionControl.Client"#>
<#@ assembly name="Microsoft.TeamFoundation.ProjectManagement"#>


<#@ import namespace="Microsoft.TeamFoundation.Client"#>
<#@ import namespace="Microsoft.TeamFoundation.VersionControl.Client"#>


<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="EnvDTE80" #>
<#@ output extension=".cs" #>
<#
DTE dte=null;
var serviceProvider = Host as IServiceProvider;
    if (serviceProvider != null) {
        dte = serviceProvider.GetService(typeof(DTE)) as DTE;
    }
	if (dte == null) {
        throw new Exception("generate build number can only execute through the Visual Studio IDE");
		}
ProjectItem projectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
int netVersion=0;

var proj=projectItem.ContainingProject;
var configmgr = proj.ConfigurationManager;
var config = configmgr.ActiveConfiguration;
string regex=@"^.+?Version=v(?<version>\-?\d+\.\d+).*?$";
var options = RegexOptions.Multiline;
string input= proj.Properties.Item("TargetFrameworkMoniker").Value.ToString();
	
MatchCollection matches = Regex.Matches(input,regex,options);
foreach (Match match in matches)
{
		
    netVersion = (int)(double.Parse(match.Groups["version"].Value)*100);
		
}


string filePath = proj.FullName;
string dirPath = System.IO.Path.GetDirectoryName(filePath);
var wsInfo = Microsoft.TeamFoundation.VersionControl.Client.Workstation.Current.GetLocalWorkspaceInfo(filePath );
 
 // Get the TeamProjectCollection and VersionControl server associated with the
 // WorkspaceInfo
 var tpc = new TfsTeamProjectCollection(wsInfo.ServerUri);
 var vcServer = tpc.GetService<VersionControlServer>();
 
 // Now get the actual Workspace OM object
 var ws = vcServer.GetWorkspace(wsInfo);
 
 // We are interested in the current version of the workspace
 var versionSpec = VersionSpec.Latest;
 
 var historyParams = new QueryHistoryParameters(dirPath, RecursionType.Full);
 historyParams.ItemVersion = versionSpec;
 historyParams.VersionEnd = versionSpec;
 historyParams.MaxResults = 1;
 
 var changeset = vcServer.QueryHistory(historyParams).FirstOrDefault();


 var dt = DateTime.Now;
var userName = System.Security.Principal.WindowsIdentity.GetCurrent().Name;
userName = userName.Split('\\').Last();

 #>
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following 
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BuildTraceabilityDemo")]
//http://www.codeproject.com/Articles/118909/Windows-7-File-properties-Version-Tab-Shell-Extens
[assembly: AssemblyDescription("BuildDate,<#=dt.ToString("yyyyMMdd_HHmmss")#>\r\n<#=proj.Properties.Item("TargetFrameworkMoniker").Value.ToString()#>\r\nBuild by,<#=userName#>\r\nConfig,<#=config.ConfigurationName#>,\r\nChangeset,<#=changeset.ChangesetId#>")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("BuildTraceabilityDemo")]
[assembly: AssemblyCopyright("Copyright ©  <#= dt.Year#>")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

// Setting ComVisible to false makes the types in this assembly not visible 
// to COM components.  If you need to access a type in this assembly from 
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("75ff7863-cb83-4d9b-80de-4a0de2781918")]

// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version 
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers 
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.<#=dt.Year#>.<#=dt.Month#>.<#=dt.Day#>")]


   

Video : http://youtu.be/A_qSdVV93qk

Demo project here : https://traceabilitydemo.codeplex.com/releases/view/132231

Source code here : https://traceabilitydemo.codeplex.com/SourceControl/changeset/view/110446

Traceability in .NET–.tt files–add build date– part 4 of 7

Firstly we propose that build can automatically put the data in AssemblyVersion. For this you will need somehow to generate the current date.

We can do this in several ways – for example, a post build event. We will use a .tt file that will automatically generate this date. We will use for other things – for example, last checkin of TFS.

Running .tt files can be done either via command Build => Transform all T4 templates or in a before build event solution here . The solution is taken from http://stackoverflow.com/questions/1646580/get-visual-studio-to-run-a-t4-template-on-every-build – run in pre-build event the .tt file.

You can download demo project from here: https://traceabilitydemo.codeplex.com/releases/view/132229

Source code: https://traceabilitydemo.codeplex.com/SourceControl/changeset/view/110438

Video : https://www.youtube.com/watch?v=lZJ1NCIDejU

Next time we will add the TFS checkin id

Tracebility in .NET -source control – part 3 of 7

Adding version with Source Control

This depends on what source control do you use . We will not discuss this in details – it is enough to searchAssemblyVersion. For TFS or SVN you can use https://github.com/loresoft/msbuildtasks : TfsVersion si SvnVersion

You can use command line too : http://www.woodwardweb.com/vsts/determining_the.html

Full tutorial with powershell you can find at http://blogs.msdn.com/b/visualstudioalm/archive/2013/07/24/basic-tfbuild-scripts.aspx http://msdn.microsoft.com/en-us/library/dn376353.aspx#env_vars http://curah.microsoft.com/8047/run-scripts-in-your-team-foundation-build-process

I have made a video at : https://www.youtube.com/watch?v=teiSgEYZXog

I can send source code –it is on visualstudio.com

Traceability in .NET – 1 of 7

What is traceability?

From Wikipedia, http://en.wikipedia.org/wiki/Traceability :
Traceability is the ability to verify the history, location, or application of an item by means of documented recorded identification.
We define traceability in software tracking capabilities and implementation of software components to know exactly:
1 The date the component was done (so that we can reproduce the source code)
2 Details of the production (version frameworks, other components, compilation debug / release, other data) so as to have the ability to distinguish between different versions
Assume that we have already answered yes to step 1 (Do you use source control?) from http://www.joelonsoftware.com/articles/fog0000000043.html
Also (although we do not use;)) is good to study and Semantic Version http://semver.org/

Why we need traceability in software

Suppose we have a source code that you distribute one to several customers. Suppose we modify the code for version two. Some of his old clients make software upgrades – others not. If a customer reports a bug, how do we know which version of the source code had problems?

ASP.NET MVC–find error

I am moderator and a frequent answerer at forums.asp.net . Mostly of time the error is in thinking that database connection errors belong to MVC – or other things that are part of the .NET framework, not of MVC . However , I must write here the most confusing problem  that I have encountered:

<start quoting>

“I have an XML file, whose contents I want to display on the browser window using ASP drop down list and LINQ to XML. I am using Visual Studio MVC 4 for this purpose. In the model folder I have created a file to access the XML file, whose contents are :

[… not important code]

In the view folder, I have a asp file as shown

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="MvcApplication7.Controllers.QueryController" CodeBehind="~/Controllers/QueryController.cs" %>


<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

    <div id="updatePanel">
        <asp:DropDownList runat="server" ID="fragment">
        </asp:DropDownList>

    </div>

</asp:Content>
 

And finally in the Controller folder, I have

 namespace MvcApplication7.Controllers
    {
        public class QueryController : System.Web.UI.Page
        {
            //
            // GET: /Query/

        protected void Page_Load(object sender, EventArgs e)
        {
                fragment.DataSource = MvcApplication7.Models.fragmentNameModels.GetFragmentName();
                fragment.DataTextField = "id";
                fragment.DataValueField = "id";
                fragment.DataBind();
        }
 }
}
 

The ID given to the drop down list is "fragment", but when i use it my controller file I get the following error message :

Error 1 The name 'fragment' does not exist in the current context “

 

<end quoting>

Could you spot the error?

Then re-read the post and found the confusing things that will make assumption that is MVC ( including original poster words, comments and code)

 

( And , if not, the answer is here http://forums.asp.net/t/1974367.aspx?The+name+________+does+not+exist+error+Advice+needed+ASAP+ )

 

 

 

Foursquare–part 4–conclusions

Part 1: beginning using API: http://msprogrammer.serviciipeweb.ro/2014/01/27/foursquarepart-1-of-4/

Part 2: Trying PC version: http://msprogrammer.serviciipeweb.ro/2014/02/16/foursquarepart-2-of-4/

Part 3: Improving PC version: http://msprogrammer.serviciipeweb.ro/2014/02/24/foursquarepart-3-of-4/

Part 4: conclusions( this blog post)

 

First conclusion : web is media of choice . The programmers makes API easier for connecting via Web, not via every device. ( although FourSquare have developed native classes  for IOS / Android )

Second conclusion :  with reasonable effort  you can make a version that runs on every platform ( ok, not trying yet Windows phone, but it should not be so different – requires the browser to login). And you will find some implementation that parses the Web Json.

Third  conclusion : Be aware of API changes and prepare for a sustainable effort if the platform is making breaking changes .Those can come from request (https://developer.foursquare.com/overview/versioning : << As of January 28, 2014, requests that do not include a v parameter will be rejected.  >> ) or from response ( http://msprogrammer.serviciipeweb.ro/2014/02/09/solving-no-parameterless-constructor-defined-for-type-of-system-string/ , transforming a string icon property into a class)

 

Final:

It is nice to play with a third party and get the data programmatically.   For example, with the program I just show , I save a text file with my daily activities and put on onedrive :

20140301 214229,Cinema City,
20140301 213600,AFI Palace Cotroceni,
20140301 203400,Ministerul Finanțelor Publice,
20140301 170706,casa,
20140301 163738,Carrefour,
20140301 151818,Gett’s Color Bar,
20140301 142525,Cărturești,
20140301 141331,AFI Palace Cotroceni,
20140301 133653,Catedrala Sfântul Iosif (St. Joseph’s Cathedral),
20140301 122913,World Class Health Academy Downtown,
20140301 120617,McDonald’s,
20140301 103729,Piața Romană,
20140301 095350,Dedeman,
20140301 075136,Dedeman,
20140301 053653,casa,

 

And relax 

Photo

 

 

Made by Andrei Ignat, http://msprogrammer.serviciipeweb.ro
Source code at https://github.com/ignatandrei/4SqDayHistory
View online at http://fsq.apphb.com

Solving “No parameterless constructor defined for type of ‘System.String’.”

TL;DR

If you have the problem

No parameterless constructor defined for type of ‘System.String’!

just add the DeserializeObject and InterceptError functions , add this 2 lines:

var obj = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json); //json parameter is the string content of the api
<your object> = DeserializeObject(obj, typeof(<your object type>)) as <your object type>; 

watch the debug window and you will see the problems marked with !!!
( See also video at http://youtu.be/7oZ37pnSNtM)

Long story:

I wanted to do a tutorial for obtaining data from foursquare from Web , Desktop and mobile applications. I have made some research first and I have discovered the API and a library for obtaining data.

Unfortunately, foursquare changed his API and , when deserializing, the application was giving  

“No parameterless constructor defined for type of ‘System.String’.

 

at this line

fourSquareResponse = new JavaScriptSerializer().Deserialize<FourSquareSingleResponse<T>>(json);

I have made a custom code to see where the errors are. 

I do not want to explain the code, just look at it and then I will show how to use:

/// <summary>
        /// TODO: make this add to global errors to return to the caller
/// </summary>
        /// <param name="message"></param>
        private void InterceptError(string message)
        {
            var cc = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(message);
            Console.ForegroundColor = cc;
            Debug.WriteLine(message);
        }
        private object DeserializeObject(Dictionary<string, object> dictItem, Type tip)
        {
            
            var newInstance = Activator.CreateInstance(tip);
            var isDictionary = (tip.GetInterface("IDictionary") != null);
            PropertyInfo p = null;
            foreach (var k in dictItem.Keys)
            {
                var ser=  new JavaScriptSerializer().Serialize(dictItem[k]);

                
                Type tipP = null;
                if (isDictionary)
                {
                    tipP = tip.GetGenericArguments()[1];
                }
                else
                {
                    
                    try
                    {
                        p = tip.GetProperty(k);
                        if (p == null)
                            throw new ArgumentNullException(k);
                    }
                    catch (Exception)
                    {
                        //Console.WriteLine(ex.Message);                        
                        InterceptError("missing property:" + k + " to class" + tip.FullName + " value:" + ser);
                        continue;
                    }
                    tipP = p.PropertyType;
                }
                
                
                if (tipP.IsClass && tipP.FullName != typeof(string).FullName)
                {
                    
                    dynamic val = null;
                    try
                    {
                        val = new JavaScriptSerializer().Deserialize(ser, tipP);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("error for class:" + k + ex.Message);
                        IList arr = dictItem[k] as object[];
                        if (arr == null)
                        {
                            arr = dictItem[k] as ArrayList;
                        }
                        if (arr == null)
                        {                            
                            var t1 = dictItem[k] as Dictionary<string, object>;
                            if (t1 == null)
                            {
                                InterceptError("Not a dictionary, not an array - please contact ignatandrei@yahoo.com for " + k);
                            }

                            val = DeserializeObject(dictItem[k] as Dictionary<string, object>, tipP);
                            
                        }
                        else
                        {
                            val = Activator.CreateInstance(tipP);
                            var tipGen=tipP.GetGenericArguments()[0];
                            foreach (var obj in arr)
                            {
                                val.Add((dynamic)DeserializeObject(obj as Dictionary<string, object>, tipGen));
                            }
                        }
                        

                    }

                    if (isDictionary)
                    {
                        ((IDictionary)newInstance).Add(k, Convert.ChangeType(val, tipP));
                    }
                    else
                    {
                        p.SetValue(newInstance, Convert.ChangeType(val, tipP), null);

                    }
                }
                else//simple int , string, 
                {
                    try
                    {
                        if (isDictionary)
                        {
                            ((IDictionary)newInstance).Add(k, Convert.ChangeType(dictItem[k], tipP));
                        }
                        else
                        {
                            p.SetValue(newInstance, Convert.ChangeType(dictItem[k], tipP), null);
                        }
                    }
                    catch (Exception ex)
                    {
                        InterceptError("!!!not a simple property " + k + " from " + tip + " value:" + ser);
                    }
                }
            }
            return newInstance;
        }

Now the original code that throws the error looks this way:

try
            {
                fourSquareResponse = new JavaScriptSerializer().Deserialize<FourSquareSingleResponse<T>>(json);  //json parameter is the string content of the api
            }
            catch (Exception ex)
            {
                var obj = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(json);  //json parameter is the string content of the api
                fourSquareResponse = DeserializeObject(obj, typeof(FourSquareSingleResponse<T>)) as FourSquareSingleResponse<T>; 
            }

When looking to the debug window, you will see:

!!!not a simple property icon from FourSquare.SharpSquare.Entities.Category value:{"prefix":"https://ss1.4sqi.net/img/categories_v2/building/home_","suffix":".png"}

 

If looking to the source code, you will see

public string icon
        {
            get;
            set;
        }

And in the foursquare api you will see

 

    • icon: {
      • prefix: "https://ss1.4sqi.net/img/categories_v2/travel/trainstation_"
      • suffix: ".png"

      }

  •  

    Now it is clear : icon is not a string, is a class!
    So just add a class with required properties , modify the property from string to this class and it is all solved!
    ( for me, the class is:

       public class Icon
       {
           public string prefix { get; set; }
           public string suffix { get; set; }
    
        }
    

    and the definition will be:

    public Icon icon
            {
                get;
                set;
            }
    

    Moral of the story:

    When obtaining data via HTTP API, just be sure that you can handle modifications!

    Foursquare–part 1 of 4

    I have decided to log my daily routine from FourSquare .  I decided to make a Web application and a desktop application ( console, to be easiear) .

    As a good application, 4Sq have an API at https://developer.foursquare.com/ . I suggest you to start with conecting to 4Sq, https://developer.foursquare.com/overview/auth .

    For WebServers , you will redirect the user to  an URL from 4Sq.

    https://foursquare.com/oauth2/authenticate
        ?client_id=YOUR_CLIENT_ID
        &response_type=code
        &redirect_uri=YOUR_REGISTERED_REDIRECT_URI

    The user gives his accept to use your application and 4Sq redirects the browser back to YOUR_REGISTERED_REDIRECT_URI

    Then , with the code, you can ask for an access token and then you can search 4Sq API.

    I have searched also a 4Sq application in .NET   – and I found this one : https://github.com/ignatandrei/SharpSquare

    Ok, so for implementing with ASP.NET MVC it is relatively simple – I must make an action that can answer to YOUR_REGISTERED_REDIRECT_URI and then ask for user checklist for the previous day – rather simple:

     public ActionResult oldWay(string id)
            {
                var c = new conect4Sq();
                c.SetAccessCode(id);
                var data = c.CheckinsYesterday();
                return View("~/Views/Home/ShowCheckins.cshtml",data);//TODO: use T4MVC
    
            }
    

    You can see the application in work at http://fsq.apphb.com/  – just press the first “learn more” from the left.

    You will find  the source code at https://github.com/ignatandrei/4SqDayHistory

    Problem solved !

    Now the real problem is to do the same thing from a DESKTOP application ( or Console, to be easier) – but this will be in the second part next week!

    Javascript MVVM and ASP.NET MVC

    TL;DR;

    The purpose of this article is to show is how to transmit data to edit( create, update, delete) from a MVVM array to an ASP.NET MVC action in order for the action to bind to an IEnumerable/Array/List of objects. We will make also a javascript function that can be re-use across multiple MVVM frameworks to transmit data for multiple objects at once.

    As always, you can find source code at https://github.com/ignatandrei/JavaScriptAndMVVMandMVC/ and you can view online at http://mvvmjavascriptmvc.apphb.com/

     

    If you know already that, the last item on this rather long post is a homework. Download code and do it Winking smile

     

     

    Prerequisites:

    1. If you want to know about ajax, please see the same example of how to save employee one by one http://msprogrammer.serviciipeweb.ro/2011/12/05/jquery-ajax-request-and-mvcdetailed/.
    2. The reference of sending an array of objects to MVC is http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ . Please read it first since we will compose the Http request in ASP.NET MVC manner.
    3. If you do not know about MVVM and data binding in javascript, please follow most comprehensive tutorial that I know, http://learn.knockoutjs.com/

    Objects

    We start with the Employee ( Id, Name and IdDepartment) and Department(Id, Name). We will make an interface to display and edit multiple employees. The user can choose to change the Name and pick a Department from a list of Departments (presented as a select / dropdown / combox) .Also, he can create new Employee or delete an existing Employee. Then the user can submit all changes at once. We will use for this MVVM from Knockout, but you can use any other MVVM framework.

    We will have 2 modes: edit and display. For edit, we have as actions add, delete ,modify and send all modifications(along with validation) . I would list what it is mandatory for every mode and action.

    For fast learners:
    Display
    Edit Mode –Modify existing data
    Edit Mode –add new employee
    Edit Mode –delete existing employee
    Edit Mode –send modifications and client validation
    Summary
    Homework


    Display:

    clip_image002

    As you see we need to display the Employee list with name and the Department name.

    If I do not want to create a NameDepartment property on Employee, but just use DepartmentId then the Model of the View should return the list of names of Departments.

    public class ListEmployeesViewModel
    
    {
    
    public employeeList AllEmployees { get; set; }
    
    public departmentList DepartmentList{ get; private set; }
    

    This will be serialized as javascript array in the Home view:

    @{
    
    var jss = new JavaScriptSerializer();
    
    var arrDepartments = jss.Serialize(Model.DepartmentList);
    
    var arrEmployees = jss.Serialize(Model.AllEmployees);
    
    }
    
    //This is in the script tag in javascript:
    //existing departments
    
    var arrDeps = @Html.Raw(arrDepartments) ;
    
    //existing employees
    
    var arrEmps = @Html.Raw(arrEmployees) ;
    
    
    

    So we have in arrDeps the departments and in arrEmps the existing employees.

    To display the list of employees we create a MVVM javascript model( we have here knockout style, but is similar with other javascript MVVM framework)

    First we create an employee in javascript ( explanations will follow) :

    //this is in javascript
    var emp = function(empId,name,deptId,active){
    
    var self = this;
    
    self.nr = i++; 
    
    self.IdEmployee = ko.observable(empId);
    
    self.NameEmployee = ko.observable(name);
    
    self.Active = ko.observable(active);
    
    self.iddepartament = ko.observable(deptId);
    
    self.editMode = ko.observable(false);
    
    self.displayMode= ko.observable(true);
    
    self.deptName= function(){
    
    var id=self.iddepartament();
    
    var name ="";
    
    $.each(arrDeps,function(index,value){
    
    if(value.IdDepartment == id){
    
    name=value.NameDepartment;
    
    return false;
    
    }
    
    });
    
    return name;
    
    }
    
    }
    

    Explanation 1: the nr is the number of the employee . The user does not like ID, but wants to know how much employees are displayed.

    Explanation 2: I have add an editMode and displayMode to the employee – to know the mode in which the employee is. I can have one property instead of 2(because of complementarity) , but was easier for me.

    Explanation 3: In order to display DepartmentName it is enough to create a function on the employee to return the department name , iterating through the arrDeps – the code is

    self.deptName= function(){
    
    var id=self.iddepartament();
    
    var name ="";
    
    $.each(arrDeps,function(index,value){
    
    if(value.IdDepartment == id){
    
    name=value.NameDepartment;
    
    return false;
    
    }
    
    });
    
    return name;
    
    }
    

    Now we create the javascript model that holds all employees on the view:

    var jsModel = function() {
    
    var self = this;
    
    self.employees = ko.observableArray([]);
    
    

    And we make a function to add the existing employees to the array of employees:

    self.addEmp = function(empId,name,deptId,active) { 
    
    self.employees.push(new emp(empId,name,deptId,active)) 
    
    };
    

    And we add to the javascript MVVM model the existing employees

    var model= new jsModel();
    
    $.each(arrEmps,function(index,value){
    
    model.addEmp(value.IdEmployee ,value.NameEmployee, value.iddepartament,value.Active);
    
    });
    

    And display it on the template by just binding :

    ko.applyBindings(model);
    

    that will repeat in

    <tbody data-bind=’foreach: employees’>

    <tr>

    <td>

    <span data-bind=’text: nr’ > </span>

    </td>

    <td>

    <span data-bind=’text: NameEmployee,visible:displayMode’> </span>

    <!—code removed for clarity–>

    </td>

    <td>

    <span data-bind=’text: deptName(),visible:displayMode’> </span>

    <!—code removed for clarity–>

    </td>

    <td>

    <span data-bind=’text: Active,visible:displayMode’> </span>

    <!—code removed for clarity–>

    </td>

    <td><!—code removed for clarity–>

    </td>

    </tr>

    So this was the display mode. Pretty simple, huh ?

    Edit Mode –Modify existing data

    The Edit button calls the javascript model edit(true):

    self.edit = function(val){
    
    var arr =self.employees();
    
    $.each(arr ,function(index,value){
    
    value.editMode(val);
    
    value.displayMode(!val);
    
    });
    

    So I put editMode to true and displayMode to false

    Now, back to the template:

    <td>

    <span data-bind=’text: NameEmployee,visible:displayMode’> </span>

    <input data-bind=’value: NameEmployee,visible:editMode’ />

    </td>

    You can see here visible attribute binded on displayModel and editMode –and how the span or the input are visible either way.

    clip_image004

    Same for the checkbox and the select. Because of the MVVM (in this case, knockout) any changes on the data ( name, active, changing department) will be binded back to the array of employees in the javascript MVVM model

    Edit Mode –add new employee

    When you press add a new employee is generated – the number 3:

    clip_image006

    It is easy – the Add button calls the same function addEmp that we use to push existing employees:

    function BeginAdd(){
    
    model.addEmp(0,'',0,true);
    
    model.edit(true);
    
    }
    

    So a new employee is added to the array of employees – and the employees table is displaying the added employee . Do you like MVVM now ? 😉

    Edit Mode –delete existing employee

    The delete button have this code:

    <td><button data-bind="click: $root.removeEmp,visible:editMode">Delete</button></td>

    It is clear visible just when editMode is true. And the removeEmp removes the current employee from array, but having the id ( if not 0 – means new) put into a string that contains the ids of deletedEmployeesa:

     self.removeEmp = function(emp) { 
    
    var id=emp.IdEmployee(); 
    
    if(id != 0)
    
    self.deletedItemsId += id;
    
    self.employees.remove(emp); 
    
    };
    

    And the employees table is removing the row for the employee . Do you like MVVM now ? 😉

    Edit Mode –send modifications and client validation

    On the server side, the parameters of the action that receives the data is simple:

    [HttpPost]

    [HttpPost]
    
    public JsonResult SaveEmployees(ListEmployeesViewModel e,string deletedItems)
    

    I will explain the 2 arguments. For the first, remember ListEmployeesViewModel from the beginning ? It contains the list of employees and we will post that:

    public class ListEmployeesViewModel
    
    {
    
    public employeeList AllEmployees { get; set; }
    

    The second argument is the string that contains the id’s of deletedEmployees.

    Now to transmit those from javascript array of employees.

    Being a programmer, I like code-reuse. So why not create a function that iterates through an array( of employees), get all properties ( eliminating non-relevant, such as nr, editMode, displayModel and others) and compose the data in the MVC style(http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ )

    First, we need reflection in javascript:

    
    //this is generic and can be put in a different .js file
    
    var refProps= function (obj, exclude , recognizeFunction) {
    
    var properties = [];
    
    for (var prop in obj) {
    
    //you can define an exclude function to exclude added properties
    
    if(exclude){
    
    if(exclude(prop))
    
    continue;
    
    }
    
    var excludeProp = true;
    
    var t = (typeof obj[prop]).toLowerCase();
    
    if (t == 'number' || t == 'string' || t == 'boolean') {
    
    excludeProp=false;
    
    }
    
    if(excludeProp){
    
    //special case :maybe it is a observable function 
    
    if(recognizeFunction){
    
    if(t == 'function' ){
    
    if(recognizeFunction(t))
    
    excludeProp=false;
    
    }
    
    };
    
    }
    
    if(!excludeProp)
    
    properties.push(prop);
    
    };
    
    return properties;
    
    }
    
    

    Fast explanation of parameters:

    1. obj is the object in javascript that I need all properties that are number, string, or boolean.
    2. I need to remove some properties(nr,editMode, displayMode) that are relevant in javascript – but not on the server side – so I have put an exclude function( you can put null)
      function exclude(prop){
      
      switch(prop){
      
      case "nr":
      
      return true;
      
      case "deptName":
      
      return true;
      
      case "editMode":
      
      return true;
      
      case "displayMode":
      
      return true;
      
      default:
      
      return false;
      
      }
      
      
    3. Also, knockout make a special ko.observable function
      self.NameEmployee = ko.observable(name);
      

      – so I need to recognize those functions – and the function is(surprise!) ko.observable

    Now saving the array is again re-usable:

    function saveArray(itemsArray,/*you can not pass those*/prefix, excludeProp,recognizeFunction,validateProp){
    
    var l = itemsArray.length ;
    
    if(l == 0){
    
    return "";
    
    }
    
    var propNames = refProps(itemsArray[0],excludeProp,recognizeFunction); // you can pass null on exclude to add all properties
    
    var nr = 0 ;
    
    var strData="";
    
    for (var i = 0; i < l; i++) {
    
    var objToSave= itemsArray[i]; 
    
    //you can pass here another function to recognize which object can be saved
    
    //if(!canBeSaved(objSave) continue;
    
    for (var j = 0; j < propNames.length; j++) {
    
    var nameProp = propNames[j];
    
    var val =objToSave[nameProp] ;
    
    var t = (typeof val).toLowerCase();
    
    if(t == 'function'){
    
    val = objToSave[nameProp]();
    
    }
    
    if (validateProp) {
    
    if (!validateProp(nameProp,val, objToSave, i)) {
    
    return "";
    
    }
    
    }
    
    strData += "&"+ prefix+"[" + nr + "]." + nameProp;
    
    strData += "=" + val;
    
    }
    
    nr++;
    
    }
    
    return strData;
    
    }
    
    
    

    The itemsArray parameter is the items array that you want to save ( in my case, the employees).

    The new function is validateProp – you can pass null – but this is an implementation that take into consideration that the employee should not have the name empty and the user must select something from the department list:

    
    function validateProperty(propName, value, item, number){
    
    switch(propName){
    
    case "NameEmployee":
    
    if(value == ""){
    
    window.alert("please enter employee name for row number " + (number+1) );
    
    return false;
    
    }
    
    return true;
    
    case "iddepartament":
    
    if(value === undefined || value == 0){
    
    window.alert("please select a department for row number " + (number+1) );
    
    return false;
    
    }
    
    return true;
    
    default:
    
    return true;
    
    }
    
    }
    
    
    
    

    After those 2 re-usable functions( saveArray and refProps ) the code for save is pretty simple:

    We obtain the values for employees using saveArray

    self.save = function() { 
    
    var itemsArray = self.employees();
    
    var strData = saveArray(itemsArray,"AllEmployees",exclude, ko.observable,validateProperty);
    
    if(strData == "")
    
    {
    
    //window.alert("no save");
    
    return;
    
    }
    
    strData="deletedItems=" +self.deletedItemsId + strData;
    
    window.alert("saving:" + strData);
    
    

    and post to the server.

    
    $.ajax({
    
    type:"POST",
    
    url:'@Url.Content("~/Home/SaveEmployees")' ,
    
    data: strData ,
    
    datatype:"JSON",
    
    //Just we must be attentive: if success , then the id of the new employees( those with id’s 0) must be replaced by the id’s of the id’s generated on server.
    //How I identify if multiple new employees? Well, it is easier to delete all employees with id’s 0 and add the id’s that are not already in the array:
    
    var dels=[];
    
    //delete the new items and add the new ones
    
    var idExisting=';';
    
    $.each(self.employees(), function(index,emp) {
    
    if(emp.IdEmployee() == 0 )
    
    dels.push(emp);
    
    else
    
    idExisting += emp.IdEmployee()+";";
    
    });
    
    $.each(dels,function(index,emp) {
    
    self.removeEmp(emp);
    
    });
    
    //add new one
    
    window.alert('add new ones');
    
    $.each(returndata.emps,function(index,emp) {
    
    var id=emp.IdEmployee;
    
    if(idExisting.indexOf(";" + id+";") == -1){// not found - means it is a new one
    
    self.addEmp(emp.IdEmployee ,emp.NameEmployee, emp.iddepartament,emp.Active);
    
    }
    
    });
    
    
    

    Also, for Antiforgery token I have used this code

     //added antiforgery token
                    var aft= $('input[name="__RequestVerificationToken"]');
                    if(aft.length){
                        strData +="&__RequestVerificationToken=" + aft.val();
                    }
    

    Well, that was it !

    Summary:


    We have had an javascript array of employees to edit and send data at once . We have make the POST as for ASP.NET MVC rules. You can re-use the refProps javascript function( that gives you the name of the properties of an object – in our case, employee) and saveArray javascript function – that serialize an javascript array to a recognizable ASP.NET MVC idiom

    As always, you can find source code at https://github.com/ignatandrei/JavaScriptAndMVVMandMVC/ and you can view online at http://mvvmjavascriptmvc.apphb.com/

     

    Homework for you:

    ( fork on github  and send me the solution via github)


    1. Modify the nr ( the employee order number) such as , when deleting or adding a new employee, the numbers are in good order – not 1 and 3 like in the picture

    clip_image008

    2. Add a hiredate to the employee . Ensure you transmit the date(Hint: Modify the refProps )

    LaterEdit:
    Hintea Dan Alexandru made a simple application to show me that a simple json.stringify it is enough for MVC to do this magic.
    More , it shows directly in the MVVM model a toDTO that is simplier to use( however, the validation part remains to do)
    Source code at https://github.com/hinteadan/MvcAjaxSample/#!