PhoneGap Cordova JSONP RSS Feeds

Introduction

I like creating apps packed with multiple functionality so without re-writing any code I can spin off a new app with a particular theme. The typical features I pack into an app are thngs like searching and displaying YouTube videos, iTunes music videos, RSS Feeds, scanner, dozens of html5 games, AdMob Ads, iOS7 Frosted Panels, and a novel GUI calledSwipeClouds™ all wrapped into a single PhoneGap Cordova mobile app under 10 megabytes. You can see a video of such a “Packed App” I called StationBreak where all these features are turned on at:
https://www.youtube.com/watch?v=lgn2lXv4szg

Or download a working copy of this app and source code from my website at:
http://www.SerGioApps.com

OR, the compiled app from Google Play at:
https://play.google.com/store/apps/details?id=com.sergioapps.stationbreak

The sample with this article I kept simple and focused on illustrating the use of JSONP RSS Feeds. The most important component in a “Packed App” is a RSS Reader. There are millions of RSS Feeds so by just setting the feeds to a particular Theme such as heath, sports, money, blogs, government grants, etc., you have created a new mobile app. If I only retrieve feeds in my app on “Dieting” then I have created the “Diet App,” or of I only retrieve Government Grants feeds (the U.S. government has over one million such feeds), the I have created the Government Grants Mobile Appwith the same RSS reader code. For most of these feeds you can use a JSONP helper service such as Google or others. But for certain cusom RSS feeds to deliver aggregate content and TV Ads to mobile apps you can’t use services like Google because they cache the responses and you have no control over the caching mechism.

There are plenty of samples of JSONP on CodeProject and the web of using PHP to return JSONP Feeds but I wanted to use a .NET Handler on my Wondows Server. So this article is about using a .NET Handler to retrieve your own, custom, non-standard JSONP RSS Feeds in a PhoneGap Cordova Mobile that support paging and Categories in Categories. Included is a “www” folder of the html5 code and SQL script to create the RSSFeeds database. The sample code also requires you have already installed Microsoft’s Northwindd Database.

The sample PhoneGap Cordova mobile app demonstrates how to retrieve a list of hundreds of Categories, and when a user clicked on an item in that list it would, in turn, display a new list of hundreds of items, and when a user clicked on one of those items it would, in turn, display a list of hundreds of items and so on and so on for as many levels deep as you wanted.

For each list of hundreds of items we display 50 items at a time and we provide “Prev” and “Next” buttons so the user can move though hundreds  of items 50 items at a time. And when a user clicks on any item we want to have the option of any one these actions occuring: occuring:

  • Clicking on an item brings up a new list of hundreds of items
  • Clicking on an item plays a single video, movie, or TV commercial
  • Clicking on an item launches a list of videos in a YouTube channel
  • Clicking on an item launches a new web page
  • Any other action you wanted to program to occur

Installing the Sample

Unzip the project file and run the SQL script, rssfeeds.sql, to create the RSSFeeds database and sample data. Also, pLease remember to change the SQL connection strings in the  web.config file to your own SQL Server.

Introducing JSONP or JSON-P

To accomplish this only requires one SQL table and a modified RSS JSONP Feed on your server to side step the same-origin policy. The same-origin policy in browsers requires certain types of data via JavaScript are restricted to where the target resource’s domain is identical to the page making the request. This policy protects users from unsafe malicious JavaScript. In PhoneGap Cordova Apps we use Cross-domain Ajax which refers to the idea of making requests across domains in opposition to the same-origin restriction. However, cross-domain Ajax is not inherently unsafe and is used in the most popular and useful apps. One mechanism which can request content cross-domain is the <script> tag. In December 2005, Bob Ippolito formally proposed JSONP (later dubbed JSON-P, or JSON-with-padding) as a way to leverage this property of <script> tags to be able to request data in the JSON format across domains. Read Bob’s idea at: http://bob.ippoli.to/archives/2005/12/05/remote-json-jsonp/

JSON-P works by making a <script> element (either in HTML markup or inserted into the DOM via JavaScript), which requests to a remote data service location. The response (the loaded “JavaScript” content) is the name of a function pre-defined on the requesting web page, with the parameter being passed to it being the JSON data being requested. When the script executes, the function is called and passed the JSON data, allowing the requesting page to receive and process the data. I won’t go into a discuss here of all the methods used or issues related to security since there are plenty of articles on those tpics here on CodeProject already. This article and sample PhoneGap Cordova Mobile App “www” folder will illustrate one way to implement your own JSONP Modified RSS Feed System on your server for mobile apps using JSONP instead of XML and WITHOUT using Google’s jsonp that caches searches which can be a big problem. This doesn’t eliminate the use of Google, YouTube, and other services but only adds another tool in your mobile tool belt.

The RSS JSONP Handler

The design concept I used was that instead of having multiple generic handlers or a single handler with lots of switch/if statement I decided to use a single generic handler with Factory design pattern. The Factory returns a class based upon the methodName that is passed which is used to only handle that request. The Factory reads the methodName and its class from the web.config file and instantiates the handler. The generic handler requests the Factory for the handler and performs some pre/post processing. The code of the ProcessRequest method of the rsshandler.ashx file is as follows:

    public void ProcessRequest (HttpContext context) {
        BaseHandler handler = null;
        try { handler = HandlerFactory.CreateHandler(context);
            if (handler != null) {
                handler.Execute();
                string output = string.Empty;
                string callbackMethodName = context.Request.Params["jsonp"];
                if (!string.IsNullOrEmpty(callbackMethodName)) {
                    string callback = string.Format(CultureInfo.CurrentCulture, 
                    "{0}({1}, '{2}');", callbackMethodName, handler.Output, handler.MethodName);
                    output += callback;
                }
                else { output = string.Format(CultureInfo.CurrentCulture, 
                    "var {0} = {1};", handler.MethodName, handler.Output);
                }
                context.Response.ContentType = "application/x-javascript";
                context.Response.Write(output);               
            }
            else { context.Response.StatusCode = 404; }
        }
        finally { if (handler != null) { handler.Dispose(); } }
    }

The CreateHandler Method

The Factory gets the request for the generic handler and executes the handler if it exists. Then, depending upon if the callback is specified or not, the result is formatted. Finally it sets the response content type and returns the response. A 404 error is thrown if the handler is not found. The Factory code reads the config file and creates the handler using reflection in the CreateHandler method as follows:

public static class HandlerFactory {
    private static readonly Assembly _currentAssembly = 
       Assembly.GetExecutingAssembly();
    public static BaseHandler CreateHandler(HttpContext context) {
        string methodName = context.Request.Params["methodName"];
        if (!string.IsNullOrEmpty(methodName)) {
            HandlerMapSection settings = 
(HandlerMapSection)ConfigurationManager.GetSection(HandlerMapSection.SectionName);
            if (settings != null) {
                HandlerMap map = settings.Maps[methodName];
                if (map != null) { BaseHandler handler = 
(BaseHandler)_currentAssembly.CreateInstance(map.TypeName, false, 
BindingFlags.CreateInstance, null, new object[] { context }, 
System.Globalization.CultureInfo.CurrentCulture, null);
                    return handler;
                }
            }
        }
        return null;
    }
}

To add a new method we just create a new class inherited from BaseHandler and make an addition to our config file as follows.

  <configSections>
    <section name="handlerMapping" type="HandlerMapSection"/>
  </configSections>
  <handlerMapping>
    <map methodName="getCustomerList" typeName="CustomerListHandler"/>
    <map methodName="Customers" typeName="CustomerHandler"/>
    <map methodName="Feeds" typeName="FeedsHandler"/>
  </handlerMapping>

Paging the RSS JSONP Feeds

One of the things i needed to add was paging through a record set for the JSONP feeds. By simply clicking the Prev and Next buttons you can page back and forward.

public static class DataHelper
{
    private static readonly string connRSSFeeds = 
    ConfigurationManager.ConnectionStrings["RSSFeeds"].ConnectionString;
    private static readonly string connNorthwind = 
    ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;

    public static List<rssfeed> GetFeeds(string cat, int start, int max)
    {
        List<rssfeed> list = new List<rssfeed>();
        const string SQL = "SELECT  [FeedId],                              " +
        "        [category],                                               " +
        "        [title],                                                  " +
        "        [author],                                                 " +
        "        [link],                                                   " +
        "        [shortDescription],                                       " +
        "        [description],                                            " +
        "        [image],                                                  " +
        "        [publishedDate],                                          " +
        "        [rank]                                                    " +
        "FROM                                                              " +
        "     (                                                            " +
        "        SELECT  [FeedId],                                         " +
        "                [category],                                       " +
        "                [title],                                          " +
        "                [author],                                         " +
        "                [link],                                           " +
        "                [shortDescription],                               " +
        "                [description],                                    " +
        "                [image],                                          " +
        "                [publishedDate],                                  " +
        "                [rank],                                           " +
        "                ROW_NUMBER() OVER (ORDER BY [rank] DESC,          " +
        "                     [publishedDate] DESC) AS [RowIndex]          " +
        "         FROM [RSSFeeds].[dbo].[Feeds] WHERE ([category] = '{0}') " +
        "     ) AS [RSSFeedsWithRowIndex]                                  " +
        "WHERE   ([category] = '{0}')                                      " +
        "AND     ([RowIndex] > {1})                                        " +
        "AND     ([RowIndex] <= ({1} + {2}))                               ";

        if (max <= 0) { max = 50; }
        List<string> feeds = new List<string>();
        using (IDbConnection cnn = CreateConnection(connRSSFeeds)) {
            using (IDbCommand cmd = cnn.CreateCommand()) {
                cmd.CommandText = string.Format(SQL, cat, start, max);
                using (IDataReader rdr = cmd.ExecuteReader()) {
                    while (rdr.Read()) {
                        RSSFeed f = new RSSFeed();
                        f.FeedId = rdr.IsDBNull(0) ? Guid.Empty.ToString() 
                                    : Convert.ToString(rdr.GetGuid(0));
                        f.category = rdr.IsDBNull(1) ? string.Empty 
                                    : rdr.GetString(1).Trim();
                        f.title = rdr.IsDBNull(2) ? string.Empty 
                                    : rdr.GetString(2).Trim();
                        f.author = rdr.IsDBNull(3) ? string.Empty 
                                    : rdr.GetString(3).Trim();
                        f.link = rdr.IsDBNull(4) ? string.Empty 
                                    : rdr.GetString(4).Trim();
                        f.shortDescription = rdr.IsDBNull(5) ? string.Empty 
                                    : rdr.GetString(5).Trim();
                        f.description = rdr.IsDBNull(6) ? string.Empty 
                                    : rdr.GetString(6).Trim();
                        f.image = rdr.IsDBNull(7) ? string.Empty 
                                    : rdr.GetString(7).Trim();
                        f.publishedDate = rdr.IsDBNull(8) ? string.Empty 
                                    : rdr.GetDateTime(8).ToLongDateString();
                        f.rank = rdr.IsDBNull(9) ? int.MinValue 
                                    : rdr.GetInt32(9);
                        list.Add(f);
                    }
                }
            }
        }
        if (list.Count == 0) { return null; }
        return list;
    }
</string></string></rssfeed></rssfeed></rssfeed>

Paging the Northwind Database

In addition, I also included a sample of one method to page through the customer records in the Northwind database in a PhoneGap Cordova Mobile App. By simply clicking the Prev and Next buttons you can page back and forward. This assumes that you already have the Northwind database installed on your server.

Our AJAX Call Isn’t To Google!!

I can understand why Google cahches requets but for many of the mobile apps I created for clients this wasn’t acceptable. So I decided to use a Handler and JSONP to create my own RSS Feeds on my own server.  Just as a note, keep in mind that in a mobile app where te user presses a button to initiate a feed request the volume of requests will be substantially less than where an app would make such a request whenever it is turned on. And where that is the case this simple approach presented has worked nicely.

   function GetRSSAds() {
    var rss_ads = store.get('rss_ads');
    if (typeof rss_ads == 'undefined') {
      store.set('rss_ads', {
        cat: 'new',
        start_index: 0
      });
      rss_ads = store.get('rss_ads');
    }
    if (rss_ads.cat.length < 1) {
      store.set('rss_ads', {
        cat: 'new',
        start_index: 0
      });
      rss_ads = store.get('rss_ads')
    }
    var _cat = rss_ads.cat;
    var _start = rss_ads.start_index;
    var _max = 50;

    <span class="style4">////////////////////////////////////</span><span class="style4">    // NOTE: We are NOT using Google !!!</span><span class="style4">    ////////////////////////////////////</span>
    //var url = 'http://www.your_website.com/rsshandler.ashx?cat=' + _cat + '&start=' + _start + '&max=' + _max + '&methodName=Feeds&jsonp=onRSSLoaded';
    var url = 'rsshandler.ashx?cat=' + _cat + '&start=' + _start + '&max=' + _max + '&methodName=Feeds&jsonp=onRSSLoaded';
    $.ajax({
      type: 'GET',
      url: url,
      async: false,
      contentType: "application/json",
      dataType: 'jsonp'
    });
  }

The RSSFeeds Database & Feeds Table

The table below created with the SQL script for this article shows how we can create a category in a category. If we put the word “category” in the category field itself then we will load a list of categories and in the link field if we have say, “#category|movies” then clicking on the “Go” button in the scrolling list will load all items from this same table with “movies” in the category field. Of course, you can customize this any way you want. What is include here is only one way of doing this.

The iOS7 Frosted Panel Look

To create an iOS7 Frosted Panel Look there are 3 “tricks” I used, namely:

  • Z-index of panel is -1. Prevent controls from being blurred

  • Panel’s Background is transparent

  • Blur what is under the panel

In order to blur or frost what is under the sliding panel I used 2 classes, namely, backfrost_on and backfrost_off, that I add and remove to “scroller_player” which is the <div> tag that holds the screen content.

   $("#panel_controls").on("panelbeforeopen", function (event, ui) {
      $('#scroller_player').removeClass('backfrost_off');
      $('#scroller_player').addClass('backfrost_on');
   });

   $("#panel_controls").on("panelbeforeclose", function (event, ui) {
      $('#scroller_player').removeClass('backfrost_on');
      $('#scroller_player').addClass('backfrost_off');
   });

   .frosted::after {
      <span class="style4">/* z-index:-1 Only blurs background, NOT controls on panel */</span>
      <span class="style4">z-index: -1 !important;</span> 
      position: absolute;
      content: "";
      right: 0;
      top: 0;
      width: 100%;
      height: 100%;
      background: rgba(255,255,255,0.5);
      -webkit-filter:blur(8px) brightness(110%);
      -moz-filter: blur(8px);
      -ms-filter: blur(8px);
      -o-filter: blur(8px);
      filter: blur(8px); 
    }

    .backfrost_on {
       -webkit-filter:blur(2px) brightness(110%);
       -moz-filter: blur(2px);
       -ms-filter: blur(2px);
       -o-filter: blur(2px);
       filter: blur(2px); 
    }
    .backfrost_off {
    }

Some Final Thoughts

Custom RSS Feeds alow you to create with minimal code dozens of different theme apps and to deliver to users information and video ads that don’t interfere with AdMob ads. There are many ways to implement custom JSONP and this article is intended to illustrate just one of those ways for PhoneGap Cordova apps.

LINK: http://www.codeproject.com/Articles/788762/PhoneGap-Cordova-JSONP-RSS-Feeds

Advertisements

Khởi tạo object sử dụng Microsoft.Practices.Unity

Khởi tạo object sử dụng Unity

using (IUnityContainer container = new UnityContainer())
{
container.LoadConfiguration();
ISprintRepository sprintRepository = container.Resolve();
developers = sprintRepository.GetDevelopers();
}

Chi tiết tại:  http://kendouiaspnetsamples.codeplex.com/SourceControl/latest#Web/TaskManager/TaskManager.Mvc/Controllers/HomeController.cs

 

ASP.NET MVC Best Practices

Editorial Note

This articles was originally at wiki.asp.net but has now been given a new home on CodeProject. Editing rights for this article has been set at Bronze or above, so please go in and edit and update this article to keep it fresh and relevant.

The ASP.NET MVC is becoming more and more popular each day.  As the application grows in size so does the maintenance nightmare.  Following are some of the better practices, that if followed, may help maintain our application and also provides a means of scalability as the demand increases.  Feel free to add/update practices/tips as required.

Do note that this checklist are just for quick reference and are not detailed materials and can be used as a quick reference.

  1. Isolate Controllers
    Isolate the controllers from dependencies on HttpContext, data access classes, configuration, logging etc.  Isolation could be achieved by creating wrapper classes and using an IOC container for passing in these dependencies
  2. IoC Container
    Use an IoC container to manage all external dependencies  The following are some of the wellknown containers/framework.

    1. Ninject
    2. Autofac
    3. StructureMap
    4. Unity Block
    5. Castle Windsor

  3. No “magic strings”
    Never use magic strings in your code. This means hard-coding view names, link text etc. into your views. Frameworks such as T4MVC can help with this.  More to come on this.
  4. Create a ViewModel for each view
    Create a specialized ViewModel for each view.  The role of ViewModel should only be databinding.  It should not contain any presentation logic.
  5. HtmlHelper
    For generating view html use HtmlHelper.  If  the current HtmlHelper is not sufficient extend it using extension methods.  This will keep the design in check.
  6. Action Methods
    Decorate your action methods with appropriate verbs like Get or Post as applicable.
  7. Caching
    Decorate your most used action methods with OutputCache attribute.
  8. Controller and Domain logic
    Try to keep away domain logic from controller.  Controller should only be responsible for

    1. Input validation and sanitization.
    2. Get view related data from the model.
    3. Return the appropriate view or redirect to another appropriate action method.
  9. Use PRG pattern for data modification
    PRG stands for Post-Redirect-Get to avoid the classic browser warning when refreshing a page after post.  Whenever you make a POST request, once the request complets do a redirect so that a GET request is fired.  In this way when the user refresh the page, the last GET request will be executed rather than the POST thereby avoiding unnecessary usability issue. It can also prevent the initial request being executed twice, thus avoiding possible duplication issues.
  10. Routing
    Design your routes carefully.  The classic route debugger comes to rescuehttp://haacked.com/archive/2008/03/13/url-routing-debugger.aspx

  11. There should be no domain logic in the views. Views must be, only, responsible for showing the data.
  12. Views should not contain presentation logic
    Views should not contain any presentation logic.  For e.g. If a “Delete” button is to be displayed only for “Admin” role this should be abstracted away in an Html Helper.  This is just an example and there will be many scenarios which will require this abstraction for easy maintenance of views.
  13. Use POST for “Delete” links instead of GET
    Using Delete links (GET) is more vulnerable than using POST.  Here is a detailed post on this along with a couple of alternatives.
    http://stephenwalther.com/blog/archive/2009/01/21/asp.net-mvc-tip-46-ndash-donrsquot-use-delete-links-because.aspx

LINK: http://www.codeproject.com/Articles/667522/ASP-NET-MVC-Best-Practices

10 lỗi quản lý: CEO quá sa đà vào công việc thường ngày

Nếu điều này nghe có vẻ quen thuộc với bạn, thì chắc hẳn bạn đang mắc phải một, hoặc một vài, trong số 10 sai lầm quản lý dưới đây

lỗi quản lý

Trên cương vị một giám đốc điều hành, bạn sẽ phải đối mặt với đủ mọi thách thức trong các giai đoạn đặc biệt khó khăn như mở rộng và phát triển thị trường, hay giữ chân những nhân viên tài năng nhất.

Tuy nhiên sau đó, cũng như nhiều nhà quản lý khác, bạn có thấy mình đang dành quá nhiều thời gian để giải quyết các vấn đề thường nhật, điều ngăn trở bạn thúc đẩy sự phát triển mạnh mẽ của các hoạt động kinh doanh không?

Warren Bennis, một chuyên gia nổi tiếng về nghệ thuật lãnh đạo công ty, đã từng nói rằng: “Quản lý là một cuộc thử nghiệm gắt gao trong cuộc đời mỗi cá nhân và quá trình đó sẽ mài giũa họ trở thành các nhà lãnh đạo”.

Phần lớn các nhà quản lý thừa nhận rằng mình phải bỏ ra 80% thời gian hay thậm chí nhiều hơn để giải quyết các công việc kinh doanh thường nhật và rất ít thời gian dành cho việc ngăn ngừa sao cho những sự kiện đó không tái xuất hiện. Nếu điều này nghe có vẻ quen thuộc với bạn, thì chắc hẳn bạn đang mắc phải một, hoặc một vài, trong số 10 sai lầm quản lý dưới đây:

1.Bạn có một viễn cảnh kinh doanh thuyết phục cho công ty của mình, một viễn cảnh phác họa tương lai công ty thật rõ nét, nhưng chỉ một vài nhân viên được nghe về nó hay có thể giải thích về nó nếu được hỏi đến.

2. Bạn có một kế hoạch kinh doanh thể hiện rõ những nhu cầu của khách hàng, nhưng cho đến nay toàn bộ công ty vẫn thất bại trong việc đánh giá các quy trình kinh doanh dựa trên kế hoạch của bạn.

3. Các mục tiêu của bạn tập trung vào việc gia tăng doanh thu và lợi nhuận, trong khi cả công ty lại thực thi chúng một cách thiếu đồng bộ, tạo ra một lưu lượng tiền mặt khiêm tốn và chỉ bận rộn với các khoản nợ mà thiếu chú ý đến việc gia tăng lợi nhuận.

4. Bạn thường xuyên nói chuyện về các nhân viên của bạn (khen hoặc chê) mà không chú ý đến những kết quả đạt được của các nhân viên cùng với các biện pháp đánh giá họ.

5. Bạn dành nhiều thời gian làm việc trong công ty của bạn theo các phương pháp, chiến thuật khác nhau, song vẫn thất bại với việc dành một lượng thời gian nhất định cho hoạt động soạn thảo các chiến lược kinh doanh, các phương pháp đánh giá công việc và các nhu cầu nguồn lực thực tế của bạn.

6. Bạn thường xuyên giao tiếp với nhân viên, nhưng lại không thể diễn giải và truyền đạt cho họ các mục tiêu kinh doanh, tình hình tài chính và thực tế hoạt động của công ty.

7. Bạn có sẵn một khoản tiền dành cho hoạt động đào tạo, nhưng vẫn thất bại trong việc đánh giá hiệu quả của các khoá đào tạo đó trong việc giúp công ty của bạn đạt được các kế hoạch đề ra.

8. Bạn không ngừng cố gắng để cải thiện hoạt động của công ty, nhưng bạn không thể so sánh hoạt động thực tế của bạn với các tiêu chuẩn bên ngoài.

9. Bạn tin rằng khách hàng, nhân viên và nhà cung cấp của bạn đều yêu thích công ty, nhưng bạn vẫn không có một quy trình nào để đánh giá sự thoả mãn của họ với những gì đang diễn ra.

10. Bạn thường xuyên đưa ra các dự đoán và các khoản ngân quỹ cần thiết, nhưng vẫn thất bại trong việc đạt được các mục tiêu đề ra từ trước, hay rút kinh nghiệm để cải thiện trong tương lai.

Các vấn đề hoạt động thường nhật luôn chiếm khá nhiều thời gian của nhà quản lý, vì thế bạn hãy tìm cách giải phóng bản thân ra khỏi các hoạt động thường nhật đó. Bạn hãy thử nhìn vào các nhiệm vụ mà bạn đang thực hiện trong lúc này. Bất kể nhiệm vụ nào liên quan đến hoạt động thường nhật đều nên được chuyển giao hay phân công cho người khác.

Nếu các nhiệm vụ này khó có thể bàn giao nhanh chóng, bạn hãy chuyển dần trách nhiệm của mình và hướng dẫn, huấn luyện cấp dưới để họ tiếp quản nhiệm vụ. Mọi nhân viên trong công ty đều có khả năng đảm đương công việc, nếu họ được đào tạo thích hợp và có đủ thời gian để tiếp nhận các kiến thức và kỹ năng cần thiết.

Kinh doanh không chỉ đơn thuần là những thành viên sáng lập, các giám đốc hay ban quản lý – những người có hiểu biết, kinh nghiệm, thông minh và …bao biện, cầu toàn, cho rằng mình có thể hoàn thành tốt nhất mọi công việc. Kinh doanh bao gồm tất cả mọi người. Trên thực tế, hoạt động kinh doanh cũng chính là con người.

Ngày nay, bạn chỉ cần 1 nhà quản lý giỏi để điều hành 100 nhân viên. Điều đó cho thấy công việc quản lý đóng vai trò quan trọng như thế nào. Như vậy, các nhà quản lý phải tập trung vào viễn cảnh, nhiệm vụ và mục tiêu của công ty, sau đó triển khai các nguồn lực để mọi việc được hoàn thành đúng theo dự kiến. Tiếp theo, hãy đánh giá, giám sát và truyền tải các kết quả để mọi nhân viên đều có đủ thông tin nhằm cải thiện chất lượng công việc.

Mặc dù sẽ vất vả hơn, nhưng bù lại nhân viên sẽ được làm việc trong tâm trạng thoải mái và họ có toàn quyền chủ động trong mọi hoạt động của mình. Cách thức này sẽ giúp nhân viên của bạn phát huy hết sở trường và khắc phục nhược điểm nhằm hoàn thành nhiệm vụ một cách tốt nhất. Và người được lợi cuối cùng sẽ không phải ai khác, mà chính là công ty của bạn

Dapper – a simple object mapper for .Net

Features

Dapper is a single file you can drop in to your project that will extend your IDbConnection interface.

It provides 3 helpers:

Execute a query and map the results to a strongly typed List

Note: all extension methods assume the connection is already open, they will fail if the connection is closed.

public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)

Example usage:

publicclassDog
{
    publicint?Age{get;set;}
    publicGuidId{get;set;}
    publicstringName{get;set;}
    publicfloat?Weight{get;set;}

    publicintIgnoredProperty{get{return1;}}
}            
            
var guid =Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id",new{Age=(int?)null,Id= guid });
            
dog.Count()
    .IsEqualTo(1);

dog.First().Age
    .IsNull();

dog.First().Id
    .IsEqualTo(guid);

Execute a query and map it to a list of dynamic objects

public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null, bool buffered = true)

This method will execute SQL and return a dynamic list.

Example usage:

 var rows = connection.Query("select 1 A, 2 B union all select 3, 4");

((int)rows[0].A)
   .IsEqualTo(1);

((int)rows[0].B)
   .IsEqualTo(2);

((int)rows[1].A)
   .IsEqualTo(3);

((int)rows[1].B)
    .IsEqualTo(4);

Execute a Command that returns no results

public static int Execute(this IDbConnection cnn, string sql, object param = null, SqlTransaction transaction = null)

Example usage:

connection.Execute(@"
  set nocount on 
  create table #t(i int) 
  set nocount off 
  insert #t 
  select @a a union all select @b 
  set nocount on 
  drop table #t",new{a=1, b=2})
   .IsEqualTo(2);

Execute a Command multiple times

The same signature also allows you to conveniently and efficiently execute a command multiple times (for example to bulk-load data)

Example usage:

connection.Execute(@"insert MyTable(colA, colB) values (@a, @b)",
    new[]{new{ a=1, b=1},new{ a=2, b=2},new{ a=3, b=3}}
  ).IsEqualTo(3);// 3 rows inserted: "1,1", "2,2" and "3,3"

This works for any parameter that implements IEnumerable<T> for some T.

Performance

A key feature of Dapper is performance. The following metrics show how long it takes to execute 500 SELECT statements against a DB and map the data returned to objects.

The performance tests are broken in to 3 lists:

  1. POCO serialization for frameworks that support pulling static typed objects from the DB. Using raw SQL.
  2. Dynamic serialization for frameworks that support returning dynamic lists of objects.
  3. Typical framework usage. Often typical framework usage differs from the optimal usage performance wise. Often it will not involve writing SQL.

Performance of SELECT mapping over 500 iterations – POCO serialization

 

Method Duration Remarks
Hand coded (using a SqlDataReader) 47ms
Dapper ExecuteMapperQuery<Post> 49ms
ServiceStack.OrmLite (QueryById) 50ms
PetaPoco 52ms Can be faster
BLToolkit 80ms
SubSonic CodingHorror 107ms
NHibernate SQL 104ms
Linq 2 SQL ExecuteQuery 181ms
Entity framework ExecuteStoreQuery 631ms

 

Performance of SELECT mapping over 500 iterations – dynamic serialization

 

Method Duration Remarks
Dapper ExecuteMapperQuery (dynamic) 48ms
Massive 52ms
Simple.Data 95ms

 

Performance of SELECT mapping over 500 iterations – typical usage

 

Method Duration Remarks
Linq 2 SQL CompiledQuery 81ms Not super typical involves complex code
NHibernate HQL 118ms
Linq 2 SQL 559ms
Entity framework 859ms
SubSonic ActiveRecord.SingleOrDefault 3619ms

 

Performance benchmarks are available here: http://code.google.com/p/dapper-dot-net/source/browse/Tests/PerformanceTests.cs , Feel free to submit patches that include other ORMs – when running benchmarks, be sure to compile in Release and not attach a debugger (ctrl F5)

Parameterized queries

Parameters are passed in as anonymous classes. This allow you to name your parameters easily and gives you the ability to simply cut-and-paste SQL snippets and run them in Query analyzer.

new{A =1, B ="b"}// A will be mapped to the param @A, B to the param @B 

Advanced features

List Support

Dapper allow you to pass in IEnumerable<int> and will automatically parameterize your query.

For example:

connection.Query<int>("select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids", new { Ids = new int[] { 1, 2, 3 });

Will be translated to:

select*from(select1asIdunion all select2union all select3)as X whereIdin(@Ids1,@Ids2,@Ids3)" // @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3

Buffered vs Unbuffered readers

Dapper’s default behavior is to execute your sql and buffer the entire reader on return. This is ideal in most cases as it minimizes shared locks in the db and cuts down on db network time.

However when executing huge queries you may need to minimize memory footprint and only load objects as needed. To do so pass, buffered: false into the Query method.

Multi Mapping

Dapper allows you to map a single row to multiple objects. This is a key feature if you want to avoid extraneous querying and eager load associations.

Example:

var sql = 
@"select * from #Posts p 
left join #Users u on u.Id = p.OwnerId 
Order by p.Id";
 
var data = connection.Query<Post,User,Post>(sql,(post, user)=>{ post.Owner= user;return post;});
var post = data.First();
 
post.Content.IsEqualTo("Sams Post1");
post.Id.IsEqualTo(1);
post.Owner.Name.IsEqualTo("Sam");
post.Owner.Id.IsEqualTo(99);

important note Dapper assumes your Id columns are named “Id” or “id”, if your primary key is different or you would like to split the wide row at point other than “Id”, use the optional ‘splitOn’ parameter.

Multiple Results

Dapper allows you to process multiple result grids in a single query.

Example:

var sql = 
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";
 
using(var multi = connection.QueryMultiple(sql,new{id=selectedId}))
{
   var customer = multi.Read<Customer>().Single();
   var orders = multi.Read<Order>().ToList();
   var returns = multi.Read<Return>().ToList();
   ...
}

Stored Procedures

Dapper supports fully stored procs:

var user = cnn.Query<User>("spGetUser",new{Id=1}, 
        commandType:CommandType.StoredProcedure).First();}}}

If you want something more fancy, you can do:

var p =newDynamicParameters();
p.Add("@a",11);
p.Add("@b", dbType:DbType.Int32, direction:ParameterDirection.Output);
p.Add("@c", dbType:DbType.Int32, direction:ParameterDirection.ReturnValue);

cnn.Execute("spMagicProc", p, commandType: commandType.StoredProcedure); 

int b = p.Get<int>("@b");
int c = p.Get<int>("@c");

Ansi Strings and varchar

Dapper supports varchar params, if you are executing a where clause on a varchar column using a param be sure to pass it in this way:

Query<Thing>("select * from Thing where Name = @Name",new{Name=newDbString{Value="abcde",IsFixedLength=true,Length=10,IsAnsi=true});

On Sql Server it is crucial to use the unicode when querying unicode and ansi when querying non unicode.

Limitations and caveats

Dapper caches information about every query it runs, this allow it to materialize objects quickly and process parameters quickly. The current implementation caches this information in a ConcurrentDictionary object. The objects it stores are never flushed. If you are generating SQL strings on the fly without using parameters it is possible you will hit memory issues. We may convert the dictionaries to an LRU Cache.

Dapper’s simplicity means that many feature that ORMs ship with are stripped out, there is no identity map, there are no helpers for update / select and so on.

Dapper does not manage your connection’s lifecycle, it assumes the connection it gets is open AND has no existing datareaders enumerating (unless MARS is enabled)

Will dapper work with my db provider?

Dapper has no DB specific implementation details, it works across all .net ado providers including sqlite, sqlce, firebird, oracle, MySQL and SQL Server

Do you have a comprehensive list of examples?

Dapper has a comprehensive test suite in the test project: http://code.google.com/p/dapper-dot-net/source/browse/Tests/Tests.cs

Who is using this?

Dapper is in production use at:

Stack Overflow , xpfest.com helpdesk, worldcitycard, roadmap

(if you would like to be listed here let me know)

LINK: https://github.com/StackExchange/dapper-dot-net

 

PRO .NET Design Pattern Framework 4.5

Tìm mãi mới thấy chú này, share để anh em nghiên cứu.

PRO Spark 4.5 is a rapid application development (RAD) platform that will code-generate 3 out of 4 layers for your apps. All with just a single mouse click. Simply create the data model for your application, tell PRO Spark where the database is and the tool will do the rest! It’s easy, quick, and powerful. PRO Spark takes care of the more mundane development tasks allowing you to develop your apps up to 4 times faster . The generated code has already been tested and conforms to the latest pattern architectures and conventions. The diagram below demonstrates the difference PRO Spark makes in your development cycle. The left side depicts development without PRO (i.e. traditional hand coding). The right side shows development with PRO giving you a huge headstart with 3 completed layers!

LINK: http://www.irdevelopers.com/post.aspx?post=PRO.NET.Design.Pattern.Framework.4.5