Wednesday, January 27, 2016

Azure Search


Azure Search Service is a fully managed cloud service that allows developers to build rich search applications using a .NET SDK or REST APIs.

It includes full-text search scoped over your content, plus advanced search behaviors similar to those found in commercial web search engines, such as type-ahead query suggestions based on a partial term input, hit-highlighting, and faceted navigation. 
Natural language support is built-in, using the linguistic rules that are appropriate to the specified language.

Azure Search is a PaaS service that delegates server and infrastructure management to Microsoft, leaving you with a ready-to-use service that you populate with search data, and then access from your application.

Azure Search stores your data in an index that can be searched through full text queries. The schema of these indexes can either be created in the Azure Portal, or programmatically using the client library or REST APIs. Once the schema is defined, you can then upload your data to the Azure Search service where it is subsequently indexed.

You can use either push or pull models to upload data to the index.

The pull model is provided through indexers that can be configured for on demand or scheduled updates (Indexer operations (Azure Search Service REST API)), allowing you to easily ingest data and data changes from an Azure DocumentDB, Azure SQL Database, or SQL Server hosted in an Azure VM.

The push model is provided through the SDK or REST APIs used for sending updated documents to an index. You can push data from virtually any dataset, as long as it’s in JSON format.

Some developers will choose an indexer for the convenience it provides. 

For other developers, the push model is worth a little extra work. Reasons for choosing a push model are twofold. First, you avoid the extra load that crawler-style mechanisms place on your data servers. Secondly, you avoid the inherent latency that comes with scheduled indexing. You’ll want search to reflect up-to-the-second status on available inventory. A push model can give you that degree of precision.


Indexes and documents

You can have multiple indexes for limits based on pricing tiers). Note that there is currently no support for joining indexes. A search request can specify one index.

Documents contain fields and associated attributes. Fields include searchable text, values used predominantly (or even exclusively) in filters and scoring profiles, and very likely – URLs or pointers to content, such as images, in other data stores. Many search applications use multiple forms of storage. Images or videos can be stored more cheaply in other storage media, such as Azure Blob storage.

Indexers can be used to schedule index updates from changed data in Azure SQL Database, SQL Server on Azure VMs, or Azure DocumentDB.

Queries can be formulated using OData syntax for Boolean filters and a simple query syntax for full-text search.

You can look up specific documents based on their ID to quickly retrieve specific items. This is useful when a user clicks on a specific search result and you want to do a look up specific details about that document.


Search application features

Full-text search (on by default for text fields) is enabled for any field having the searchable attribute. Full-text search is based on prefix matching, which means that matches are based on the first part of a search term, and not in the middle or end of word.

Scoring profiles are used to build ranking models that optimize search based on business objectives. For example, you might want newer products or discounted products to appear higher in the search results. You can also build scoring profiles using tags for personalized scoring based on customer search preferences you've tracked and stored separately.

Language support is built-in for fifty different languages, using multiple options of natural language processing stacks, including the well-known Lucene analyzers and Microsoft's own analyzers that power Microsoft Office and Bing (preview only).

Faceted navigation refers to a categorization tree used for self-directed search, often based on brands, models, sizes, or whatever categories make sense for your data. Faceted navigation is implemented through attributes in your index, combined with a facet field that is provided in a query.

Suggestions for type-ahead or autocomplete queries is supported through attributes in your index. Azure Search supports both fuzzy matching and infix matching (matching on any part of the field content). You can do both; they are not mutually exclusive.

Filters can be used to implement faceted navigation, used in query construction, or used globally to constrain search operations to filter criteria you establish in code. Filters are enabled for specific fields via your index schema, and through the $Filter search parameter.

Sort is also enabled for specific fields via the index schema and then implemented as a search parameter via the $orderBy parameter.

Count of the search hits returned for a query, and the ability to throttle how many hits are returned at a time, are implemented through $top and $skip.

Highlighted hits are specified via the highlight query parameter, and allow you to display to a user a snippet of text highlighting key words found from the search terms entered by the user.

https://msdn.microsoft.com/en-us/library/azure/dn798927.aspx?f=255&MSPPError=-2147217396


Limitations

https://azure.microsoft.com/en-in/documentation/articles/search-limits-quotas-capacity/

Azure Search does supports contains and endsWith functions that mean we cannot search like *lux* or *lux.


Reporting and analysis

Resource usage is displayed on the service dashboard so that you can quickly get an idea of how your storage is being used.

Storage consumption, document count, and index count are available in the portal. You can also use the API.

There is no built-in mechanism for measuring query throughput or other service operations. In addition, there is currently no support for logging or analysis of search results (for example, retrieving a list of search terms that yielded no results, or reporting on the origin of search requests).


References

https://azure.microsoft.com/en-in/services/search/

https://azure.microsoft.com/en-in/documentation/articles/search-what-is-azure-search/

https://msdn.microsoft.com/library/azure/dn798935.aspx

https://msdn.microsoft.com/en-us/library/azure/dn798927.aspx?f=255&MSPPError=-2147217396

https://azure.microsoft.com/en-in/documentation/articles/search-limits-quotas-capacity/















Friday, August 22, 2014

Begining with AngularJS and making simple AngularJS CRUD with Asp.NET MVC5 and Web API


What is AngularJS?
AngularJS is a JavaScript MVC framework developed by Google that lets you build well structured, easily testable and maintainable front-end applications, in other words we can say that AngularJS is an open-source JavaScript framework, maintained by Google, that assists with running single-page applications (here is a very good article that may clear up doubts related to the SPA and the Single Page Myth). Its goal is to augment browser-based applications with Model–View–Controller capability, in an effort to make both development and testing easier.

You can also refer to Angular JS Introduction for more clarifications.

Why Angular JS?

HTML is great for declaring static documents, but it falters when we try to use it for declaring dynamic views in web applications. AngularJS lets you extend your HTML vocabulary for your application. The resulting environment is extraordinarily expressive, readable and quick to develop, if you not used Angular JS yet then you have really missed out.

So the question is, are there already many other JavaScript frameworks available that makes a difference in Angular JS. Actually other frameworks deal with HTML's shortcomings by abstracting away HTML, CSS and/or JavaScript or by providing an imperative way for manipulating the DOM. Neither of these address the root problem that HTML was not designed for dynamic views.

Why I like this framework the most is its extensibility feature that makes it fully extensible and that works well with other libraries. Every feature can be modified or replaced to suit your unique development workflow and feature needs.

There are many other features that provide you a different experience of development that you may not have experienced before.

Here is the simple CRUD application made using AngularJS, MVC5 and Web API

  • Start Visual Studio 2013
  • Create a new Project
  • Select Web Template and select ASP.NET Web Application
  • Provide the name and location of website
  • Click "Next"
  • Now select MVC template and do check Web API to add folder and core references.

  • MVC template

    Now add a new model class in the model directory :

    Friend.cs

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Web;

    namespace AngularJSWebApplication1.Models
    {
        public class Friend
        {
            [Key]

            [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]

            public int FriendId { get; set; }

            public string FirstName { get; set; }

            public string LastName { get; set; }

            public string Address { get; set; }

            public string City { get; set; }

            public string PostalCode { get; set; }

            public string Country { get; set; }

            public string Notes { get; set; }
        }

    }

    Now add a context class:

    FriendsContext.cs

    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;
    using System.Web;

    namespace AngularJSWebApplication1.Models
    {
        public class FriendsContext : DbContext
        {

            public FriendsContext() : base("name=DefaultConnection")
            {
                base.Configuration.ProxyCreationEnabled = false;
            }

            public DbSet<Friend> Friends { get; set; }

        }

    }

    Now add a controller in the controller directory:

    FriendController.cs

    using AngularJSWebApplication1.Models;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;

    namespace AngularJSWebApplication1.Controllers
    {
        public class FriendController : ApiController
        {

            private FriendsContext db = new FriendsContext();

            // GET api/<controller>   
            [HttpGet]
            public List<Friend> Get()
            {
                return db.Friends.ToList();
            }


            // GET api/<controller>/5
            public Friend Get(int id)
            {
                int RequestPerSecond = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["RequestPerSecond"] ?? "1");
                Friend friend = db.Friends.Find(id);
                if (friend == null)
                {
                    throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
                }
                return friend;
            }


            // POST api/<controller>
            public HttpResponseMessage Post(Friend friend)
            {
                if (ModelState.IsValid)
                {
                    db.Friends.Add(friend);
                    db.SaveChanges();
                    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, friend);
                    response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = friend.FriendId }));
                    return response;
                }
                else
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                }
            }


            // PUT api/<controller>/5
            public HttpResponseMessage Put(Friend friend)
            {
                if (!ModelState.IsValid)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                }

                /*if (id != friend.FriendId)
                {
                    return Request.CreateResponse(HttpStatusCode.BadRequest);
                }*/

                db.Entry(friend).State = EntityState.Modified;

                try
                {
                    db.SaveChanges();
                }

                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }            
                return Request.CreateResponse(HttpStatusCode.OK);
            }


            // DELETE api/<controller>/5
            public HttpResponseMessage Delete(int id)
            {
                Friend friend = db.Friends.Find(id);
                if (friend == null)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }
                db.Friends.Remove(friend);
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK, friend);
            }
            
            protected override void Dispose(bool disposing)
            {
                db.Dispose();
                base.Dispose(disposing);
            }

        }

    }

    Now install AngularJS using Manage Nuget Package Manager.

    search AngularJS

    Now add a new JavaScript file in the scripts directory and add angular functions as follow :

    JavaScript1.js

    function friendController($scope, $http) {
        $scope.loading = true;
        $scope.addMode = false;

        //Used to display the data
        $http.get('/api/Friend/').success(function (data) {
            $scope.friends = data;
            $scope.loading = false;
        })
        .error(function () {
            $scope.error = "An Error has occured while loading posts!";
            $scope.loading = false;
        });
        
        //Used to add a new record
        $scope.toggleAdd = function () {
            $scope.addMode = !$scope.addMode;
        };
        $scope.add = function () {
            $scope.loading = true;
            $http.post('/api/Friend/', this.newfriend).success(function (data) {
                alert("Added Successfully!!");
                $scope.addMode = false;
                $scope.friends.push(data);
                $scope.loading = false;
            }).error(function (data) {
                $scope.error = "An Error has occured while Adding Friend! " + data;
                $scope.loading = false;
            });
        };

        //Used to save a record after edit
        $scope.toggleEdit = function () {
            this.friend.editMode = !this.friend.editMode;
        };
        $scope.save = function () {
            //alert("Edit");
            $scope.loading = true;
            var frien = this.friend;
            debugger;
            //alert(frien);
            $http.put('/api/Friend/', frien).success(function (data) {
                alert("Saved Successfully!!");
                frien.editMode = false;
                $scope.loading = false;
            }).error(function (data) {
                alert("Error in edit!!");
                $scope.error = "An Error has occured while Saving Friend! " + data;
                $scope.loading = false;
            });
        };
        
        //Used to delete a record
        $scope.deletefriend = function () {
            $scope.loading = true;
            var friendid = this.friend.FriendId;
            $http.delete('/api/Friend/' + friendid).success(function (data) {
                alert("Deleted Successfully!!");
                $.each($scope.friends, function (i) {
                    debugger;
                    if ($scope.friends[i].FriendId === friendid) {
                        $scope.friends.splice(i, 1);
                        return false;
                    }
                });
                $scope.loading = false;
            }).error(function (data) {
                $scope.error = "An Error has occured while Saving Friend! " + data;
                $scope.loading = false;
            });
        };


    }


    Now open BundleConfig.cs and add it :

    using System.Web;
    using System.Web.Optimization;

    namespace AngularJSWebApplication1
    {
        public class BundleConfig
        {
            // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
            public static void RegisterBundles(BundleCollection bundles)
            {
                bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                            "~/Scripts/jquery-{version}.js"));

                bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                            "~/Scripts/jquery.validate*"));

                // Use the development version of Modernizr to develop with and learn from. Then, when you're
                // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
                bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                            "~/Scripts/modernizr-*"));

                bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
                          "~/Scripts/bootstrap.js",
                          "~/Scripts/respond.js"));

                bundles.Add(new StyleBundle("~/Content/css").Include(
                          "~/Content/bootstrap.css",
                          "~/Content/site.css"));

                bundles.Add(new ScriptBundle("~/bundles/angularjs").Include(
                          "~/Scripts/angular.min.js"));

                bundles.Add(new ScriptBundle("~/bundles/myjs").Include(
                        "~/Scripts/JavaScript1.js"));
            }
        }

    }

    Now open the _Layout.cshtml page from the Shared folder and add these lines to render AngularJS and myjs in the application.

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/angularjs")
    @Scripts.Render("~/bundles/myjs")

    Now open the Index.cshtml, clear it and add following code :

    @{
        ViewBag.Title = "FriendView";
        Layout = "~/Views/Shared/_Layout.cshtml";
    }
    <h2>Friends View</h2>

    <div data-ng-app data-ng-controller="friendController" class="container">
        <strong class="error">{{ error }}</strong>

        <div id="mydiv" data-ng-show="loading">
            <img src="Images/ajax-loader.gif" class="ajax-loader" />
        </div>

        <p data-ng-hide="addMode"><a data-ng-click="toggleAdd()" href="javascript:;" class="btn btn-primary">Add New</a></p>
        <form name="addFriend" data-ng-show="addMode" style="width:600px;margin:0px auto;">
            <label>FirstName:</label><input type="text" data-ng-model="newfriend.FirstName" required /><br />
            <label>LastName:</label><input type="text" data-ng-model="newfriend.LastName" required /><br />
            <label>Address:</label><input type="text" data-ng-model="newfriend.Address" required /><br />
            <label>City:</label><input type="text" data-ng-model="newfriend.City" required /><br />
            <label>PostalCode:</label><input type="text" data-ng-model="newfriend.PostalCode" required /><br />
            <label>Country:</label><input type="text" data-ng-model="newfriend.Country" required /><br />
            <label>Notes:</label><input type="text" data-ng-model="newfriend.Notes" required /><br />
            <input type="submit" value="Add" data-ng-click="add()" data-ng-disabled="!addFriend.$valid" class="btn btn-primary" />
            <input type="button" value="Cancel" data-ng-click="toggleAdd()" class="btn btn-primary" />
            <br /><br />
        </form>
        <div id="displaytable" style="width: 100%;height: 200px;overflow: auto;">
            <table class="table table-bordered table-hover" style="width:800px">
                <tr>
                    <th>#</th>
                    <td>FirstName</td>
                    <th>LastName</th>
                    <th>Address</th>
                    <th>City</th>
                    <th>PostalCode</th>
                    <th>Country</th>
                    <th>Notes</th>
                    <th>Operations</th>
                </tr>
                <tr data-ng-repeat="friend in friends">
                    <td><strong data-ng-hide="friend.editMode">{{ friend.FriendId }}</strong></td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.FirstName }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.FirstName" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.LastName }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.LastName" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.Address }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.Address" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.City }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.City" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.PostalCode }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.PostalCode" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.Country }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.Country" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode">{{ friend.Notes }}</p>
                        <input data-ng-show="friend.editMode" type="text" data-ng-model="friend.Notes" />
                    </td>
                    <td>
                        <p data-ng-hide="friend.editMode"><a data-ng-click="toggleEdit(friend)" href="javascript:;">Edit</a> | <a data-ng-click="deletefriend(friend)" href="javascript:;">Delete</a></p>
                        <p data-ng-show="friend.editMode"><a data-ng-click="save(friend)" href="javascript:;">Save</a> | <a data-ng-click="toggleEdit(friend)" href="javascript:;">Cancel</a></p>
                    </td>
                </tr>
            </table>
        </div>
        <hr />
    </div>
    <script>
        $(document).ready(function () { $('#displaytable').jScrollPane(); })
    </script>

    Done !!!