Monday, February 15, 2016

Cách chuyển tiếng Việt có dấu thành không dấu nhanh, gọn, lẹ

Sử dụng RegularExpression, ta có thể khử dấu tiếng Việt một cách nhanh, gọn, lẹ như sau:

public static string convertToUnSign3(string s)
{
    Regex regex = new Regex("\\p{IsCombiningDiacriticalMarks}+");
    string temp = s.Normalize(NormalizationForm.FormD);
    return regex.Replace(temp, String.Empty).Replace('\u0111', 'd').Replace('\u0110', 'D');
}

Sunday, February 14, 2016

Cách zip file trong C#

Làm các bước sau để tạo file zip

B1: Tải dll Ionic.Zip từ (Lên google search ra)
B2: Giải nén, add dll từ đường dẫn: \DotNetZipLib-DevKit-v1.9\zip-v1.9\Debug\Ionic.Zip.dll
B3: Trong hàm Main, add đoạn code

                using (ZipFile zip = new ZipFile())
                {
                    zip.Password = "123";
                    zip.AddFile("Book1.xls");
                    zip.AddFile("Book2.xls");
                    zip.Save("Backup.zip");
                }

Tuesday, February 02, 2016

Sending WebDAV Requests in .NET

Earlier today one of my coworkers, John Bocharov, asked me if I had ever done any WebDAV coding in .NET - specifically sending PUT and DELETE requests. I replied that I had, but it had been several months ago, and each time that I had written any WebDAV-related code samples it was for a specific purpose and not very exhaustive. Just the same, I promised John that if I found any of my old code samples I would send them to him. After a bit of searching through my archives I was able to find enough code snippets to throw together a quick sample for PUT and DELETE that John could use, but it made me start thinking about putting together a more complete sample by adding a few extra WebDAV methods, thereby creating a better example to keep around.
With that in mind, the code sample in this blog post shows how to send several of the most-common WebDAV requests using C# and common .NET libraries. There's a bit of intentional redundancies in each section of the sample - I did this because I was trying to make each section somewhat self-sufficient so you can copy and paste a little easier. I present the WebDAV methods the in the following order:
WebDAV MethodNotes
PUTThis section of the sample writes a string as a text file to the destination server as "foobar1.txt". Sending a raw string is only one way of writing data to the server, in a more common scenario you would probably open a file using a steam object and write it to the destination. One thing to note in this section of the sample is the addition of the "Overwrite" header, which specifies that the destination file can be overwritten.
COPYThis section of the sample copies the file from "foobar1.txt" to "foobar2.txt", and uses the "Overwrite" header to specify that the destination file can be overwritten. One thing to note in this section of the sample is the addition of the "Destination" header, which obviously specifies the destination URL. The value for this header can be a relative path or an FQDN, but it may not be an FQDN to a different server.
MOVEThis section of the sample moves the file from "foobar2.txt" to "foobar1.txt", thereby replacing the original uploaded file. As with the previous two sections of the sample, this section of the sample uses the "Overwrite" and "Destination" headers.
GETThis section of the sample sends a WebDAV-specific form of the HTTP GET method to retrieve the source code for the destination URL. This is accomplished by sending the "Translate: F" header and value, which instructs IIS to send the source code instead of the processed URL. In this specific sample I am only using text files, but if the requests were for ASP.NET or PHP files you would need to specify the "Translate: F" header/value pair in order to retrieve the source code.
DELETEThis section of the sample deletes the original file, thereby cleaning off all of the sample files from the destination server.
MKCOLThis section of the sample creates a folder named "foobar3" on the destination server; as far as WebDAV on IIS is concerned, the MKCOL method is a lot like the old DOS MKDIR command.
DELETEThis section of the sample deletes the folder from the destination server.
That wraps up the section descriptions, and with that taken care of - here is the code sample:
using System;
using System.Net;
using System.IO;
using System.Text;

class WebDavTest
{
   static void Main(string[] args)
   {
      try
      {
         // Define the URLs.
         string szURL1 = @"http://localhost/foobar1.txt";
         string szURL2 = @"http://localhost/foobar2.txt";
         string szURL3 = @"http://localhost/foobar3";

         // Some sample text to put in text file.
         string szContent = String.Format(
            @"Date/Time: {0} {1}",
            DateTime.Now.ToShortDateString(),
            DateTime.Now.ToLongTimeString());

         // Define username and password strings.
         string szUsername = @"username";
         string szPassword = @"password";

         // --------------- PUT REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpPutRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpPutRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpPutRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpPutRequest.Method = @"PUT";

         // Specify that overwriting the destination is allowed.
         httpPutRequest.Headers.Add(@"Overwrite", @"T");

         // Specify the content length.
         httpPutRequest.ContentLength = szContent.Length;

         // Optional, but allows for larger files.
         httpPutRequest.SendChunked = true;

         // Retrieve the request stream.
         Stream requestStream =
            httpPutRequest.GetRequestStream();

         // Write the string to the destination as a text file.
         requestStream.Write(
            Encoding.UTF8.GetBytes((string)szContent),
            0, szContent.Length);

         // Close the request stream.
         requestStream.Close();

         // Retrieve the response.
         HttpWebResponse httpPutResponse =
            (HttpWebResponse)httpPutRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"PUT Response: {0}",
            httpPutResponse.StatusDescription);

         // --------------- COPY REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpCopyRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpCopyRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpCopyRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpCopyRequest.Method = @"COPY";

         // Specify the destination URL.
         httpCopyRequest.Headers.Add(@"Destination", szURL2);

         // Specify that overwriting the destination is allowed.
         httpCopyRequest.Headers.Add(@"Overwrite", @"T");

         // Retrieve the response.
         HttpWebResponse httpCopyResponse =
            (HttpWebResponse)httpCopyRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"COPY Response: {0}",
            httpCopyResponse.StatusDescription);

         // --------------- MOVE REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpMoveRequest =
            (HttpWebRequest)WebRequest.Create(szURL2);

         // Set up new credentials.
         httpMoveRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpMoveRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpMoveRequest.Method = @"MOVE";

         // Specify the destination URL.
         httpMoveRequest.Headers.Add(@"Destination", szURL1);

         // Specify that overwriting the destination is allowed.
         httpMoveRequest.Headers.Add(@"Overwrite", @"T");

         // Retrieve the response.
         HttpWebResponse httpMoveResponse =
            (HttpWebResponse)httpMoveRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"MOVE Response: {0}",
            httpMoveResponse.StatusDescription);

         // --------------- GET REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpGetRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpGetRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpGetRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpGetRequest.Method = @"GET";

         // Specify the request for source code.
         httpGetRequest.Headers.Add(@"Translate", "F");

         // Retrieve the response.
         HttpWebResponse httpGetResponse =
            (HttpWebResponse)httpGetRequest.GetResponse();

         // Retrieve the response stream.
         Stream responseStream =
            httpGetResponse.GetResponseStream();

         // Retrieve the response length.
         long responseLength =
            httpGetResponse.ContentLength;

         // Create a stream reader for the response.
         StreamReader streamReader =
            new StreamReader(responseStream, Encoding.UTF8);

         // Write the response status to the console.
         Console.WriteLine(
            @"GET Response: {0}",
            httpGetResponse.StatusDescription);
         Console.WriteLine(
            @"  Response Length: {0}",
            responseLength);
         Console.WriteLine(
            @"  Response Text: {0}",
            streamReader.ReadToEnd());

         // Close the response streams.
         streamReader.Close();
         responseStream.Close();

         // --------------- DELETE REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpDeleteFileRequest =
            (HttpWebRequest)WebRequest.Create(szURL1);

         // Set up new credentials.
         httpDeleteFileRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpDeleteFileRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpDeleteFileRequest.Method = @"DELETE";

         // Retrieve the response.
         HttpWebResponse httpDeleteFileResponse =
            (HttpWebResponse)httpDeleteFileRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"DELETE Response: {0}",
            httpDeleteFileResponse.StatusDescription);

         // --------------- MKCOL REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpMkColRequest =
            (HttpWebRequest)WebRequest.Create(szURL3);

         // Set up new credentials.
         httpMkColRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);

         // Pre-authenticate the request.
         httpMkColRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpMkColRequest.Method = @"MKCOL";

         // Retrieve the response.
         HttpWebResponse httpMkColResponse =
            (HttpWebResponse)httpMkColRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"MKCOL Response: {0}",
            httpMkColResponse.StatusDescription);

         // --------------- DELETE REQUEST --------------- //

         // Create an HTTP request for the URL.
         HttpWebRequest httpDeleteFolderRequest =
            (HttpWebRequest)WebRequest.Create(szURL3);

         // Set up new credentials.
         httpDeleteFolderRequest.Credentials =
            new NetworkCredential(szUsername, szPassword);
         
         // Pre-authenticate the request.
         httpDeleteFolderRequest.PreAuthenticate = true;

         // Define the HTTP method.
         httpDeleteFolderRequest.Method = @"DELETE";

         // Retrieve the response.
         HttpWebResponse httpDeleteFolderResponse =
            (HttpWebResponse)httpDeleteFolderRequest.GetResponse();

         // Write the response status to the console.
         Console.WriteLine(@"DELETE Response: {0}",
            httpDeleteFolderResponse.StatusDescription);

      }
      catch (Exception ex)
      {
         Console.WriteLine(ex.Message);
      }
   }
}
When you run the code sample, if there are no errors you should see something like the following output:
PUT Response: Created
COPY Response: Created
MOVE Response: No Content
GET Response: OK
  Response Length: 30
  Response Text: Date/Time: 2/9/2010 7:21:46 PM
DELETE Response: OK
MKCOL Response: Created
DELETE Response: OK
Press any key to continue . . .
Since the code sample cleans up after itself, you should not see any files or folders on the destination server when it has completed executing. To see the files and folders actually created and deleted on the destination server, you can step through the code in a debugger.

Closing Notes

I should point out that I did not include examples of the WebDAV PROPPATCH/PROPFIND and LOCK/UNLOCK methods in this sample because they require processing the XML responses, and that was way outside the scope of what I had originally wanted to do with this sample. I might write a follow-up blog later that shows how to use those methods, but I'm not making any promises. ;-]
I hope this helps.

Friday, January 29, 2016

Cách bypass gọi SSL trong .NET

Khi code .NET, nếu có gọi web service có https, cần bổ sung đoạn code sau để bypass SSL

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

Có nhiều cách hơn nhưng cách trên là ngắn gọn.

Nguồn tham khảo: http://dejanstojanovic.net/aspnet/2014/september/bypass-ssl-certificate-validation/

Monday, May 28, 2012

ADO.NET Entity framework advanced scenarios: Working with stored procedures that return multiple resultsets


Today I got an interesting question about stored procedures that return multiple resultsets in combination with ADO.NET entity framework. During the CTP phase this was broken at some point and the previous version of the entity framework didn’t support it at all. But as it turns out, it’s supported now and a pretty cool feature if you ask me.
In this post I will show you how to use stored procedures with multiple resultsets to return a full object graph. I will also show you some of the pitfalls that you may encounter with this scenario.

OVERVIEW OF THE SCENARIO

The scenario for this post is the database model of the recipe browser that you can find on CodePlex. It’s a sample application written in Silverlight with RIA services as a backend. The database contains recipes, that has multiple ingredients. Each of the ingredients can be expressed as a “thing” from which you need an x amount in the recipe. The table structure that I will be talking about in this post is shown below.
clip_image002
In this scenario I will be showing you a stored procedure that returns a single recipe with its ingredients, units and the categories the recipe is part of.

CREATING THE STORED PROCEDURE

The stored procedure used for the scenario is a stored procedure that retrieves a single recipe with the ingredients that are part of the recipe. It also includes the units for each of ingredients used.
For the ADO.NET entity framework to be able to work with the stored procedure, you need to follow some specific rules. Each of the design rules is discussed in the following sections of this post.

Include all columns

When you select an entity from the database you are required to include all columns mapped in the store model part of your entity model. If you don’t map all the columns you will get the following error:
The data reader is incompatible with the specified ‘RecipeBrowserModel.Recipe’. A member of the type, ‘RecipeId’, does not have a corresponding column in the data reader with the same name.

Follow the object graph to fill the children

The second important design rule that you need to keep in mind is to follow a specific pattern to map a specific entity with its children. Although it’s not required to follow this rule, it’s a makes it easier to debug a specific piece of code when you follow a specific pattern.
When mapping an object, you need to start at the root of the object graph and work your way down. At the moment, ADO.NET entity framework doesn’t support mapping a whole object graph, so the mapping is all manual code. To map the object graph in the the example, you will need to follow the pattern displayed in the diagram below. As you can see it’ follows a depth-first approach for mapping the recipe object graph.
clip_image004
The red dots in the diagram show the order in which they are returned by the stored procedure. This order is important later, when you’re going to create the stored procedure mapping as you will need to load the resultsets from the database in that exact order.

The completed stored procedure

In the end, the stored procedure used to select a recipe with its ingredients and categories isn’t all that complicated. The complete stored procedure can be found below.
   1: CREATE PROCEDURE SelectRecipeWithIngredients
   2:     @RecipeId decimal
   3: AS
   4: BEGIN
   5:     SET NOCOUNT ON;
   6:     
   7:     -- Select the recipe 
   8:     SELECT Recipe.*
   9:     FROM Recipe
  10:     WHERE Recipe.RecipeId = @RecipeId
  11:     
  12:     -- Select the categories themselves
  13:     SELECT Category.*
  14:     FROM Category
  15:     JOIN RecipeCategory ON RecipeCategory.CategoryId = Category.CategoryId
  16:     WHERE RecipeCategory.RecipeId = @RecipeId
  17:     
  18:     -- Select the ingredient information for the recipe
  19:     SELECT RecipeIngredient.*
  20:     FROM RecipeIngredient
  21:     JOIN Recipe ON Recipe.RecipeId = RecipeIngredient.RecipeId
  22:     WHERE Recipe.RecipeId = @RecipeId
  23:     
  24:     -- Select the ingredients themselves
  25:     SELECT Ingredient.* 
  26:     FROM Ingredient 
  27:     JOIN RecipeIngredient ON RecipeIngredient.IngredientId = Ingredient.IngredientId
  28:     JOIN Recipe ON Recipe.RecipeId = RecipeIngredient.RecipeId
  29:     WHERE Recipe.RecipeId = @RecipeId  
  30:  
  31:     -- Select the units that are associated with the ingredients    
  32:     SELECT Unit.*
  33:     FROM Unit
  34:     JOIN Ingredient ON Ingredient.UnitId = Unit.UnitId
  35:     JOIN RecipeIngredient ON RecipeIngredient.IngredientId = Ingredient.IngredientId
  36:     WHERE RecipeIngredient.RecipeId = @RecipeId
  37: END
  38: GO

MEET THE EF EXTENSIONS PROJECT

The stuff that is part of the entity framework in .NET framework 4 is way better than it was in v3.5, but it’s still not complete. If you are serious about stored procedures, you are going to need to add some extensions to your application that are part of the EF Extensions framework.
You can download the extensions here: http://code.msdn.microsoft.com/EFExtensions
The extensions project contains various components to make working with the entity framework easier. For example the following extensions are available:
  • Stored procedure execution customization
  • Materialization of arbitrary CLR types given a data reader or DB command.
  • Connection lifetime management.
I’m not going to discuss each of these features here. There’s just one feature we need to use for the scenario to work, namely the stored procedure execution customization.

CREATING THE STORED PROCEDURE MAPPING

Normally you would create a new function import on your entity model, but this allows for very little customization. So instead of doing that, I’m going to show you how you can use the EF extensions to map the stored procedure, so that it supports multiple resultsets.
Creating a custom stored procedure mapping starts with creating a partial class definition for theObjectContext. To this context you will need to add a new method that returns the desired entity. In this case the method has to accept a RecipeId of type decimal and will return a single recipe with its child objects.
   1: using System;
   2: using System.Collections.Generic;
   3: using System.Linq;
   4: using System.Text;
   5: using System.Data.Objects;
   6: using Microsoft.Data.Extensions;
   7: using System.Data.Common;
   8: using System.Data.SqlClient;
   9: using System.Data;
  10:  
  11: namespace StoredProcWithMultipleResultSetsSample
  12: {
  13:     public partial class RecipeBrowserEntities : ObjectContext
  14:     {
  15:         public Recipe GetRecipeWithIngredients(decimal recipeId)
  16:         {
  17:             Recipe result = null;
  18:  
  19:             //TODO: Implement this method
  20:             
  21:             return result;
  22:         }
  23:     }
  24: }
Next is the stored procedure mapping itself. You can get a hold of a stored procedure using theCreateStoreCommand extension method that is exposed when you add a using statement for theMicrosoft.Data.Extensions namespace. The result of the CreateStoreCommand method is aDbCommand that you can execute.
   1: public Recipe GetRecipeWithIngredients(decimal recipeId)
   2: {
   3:     Recipe result = null;
   4:  
   5:     SqlParameter recipeIdParameter = new SqlParameter
   6:     {
   7:         ParameterName = "@RecipeId",
   8:         DbType = System.Data.DbType.Decimal,
   9:         Value = recipeId
  10:     };
  11:  
  12:     DbCommand cmd = this.CreateStoreCommand("SelectRecipeWithIngredients",
  13:         CommandType.StoredProcedure, recipeIdParameter);            
  14:             
  15:     // Use a connection scope to manage the lifetime of the connection
  16:     using(var connectionScope = cmd.Connection.CreateConnectionScope())
  17:     {
  18:         using(var reader = cmd.ExecuteReader())
  19:         {
  20:             //TODO: Materialize the recipe.
  21:         }
  22:     }
  23:  
  24:     return result;
  25: }
Once you have the DbCommand you can execute it and materialize the results. I’m using aConnectionScope to manage the lifecycle of the connection. The using statement ensures that the connection is properly closed when the resultsets have been processed. Normally you would do this kind of operation if you were using SqlConnection or any other DbConnection class. When working with the ADO.NET entity framework however, this will be managed for you and this is just a trick to prevent problems with the framework not being able to do its job when it comes to connection management.
The final step to retrieve the data returned by the stored procedure, is to iterate over the resultsets and materialize them.
   1: public Recipe GetRecipeWithIngredients(decimal recipeId)
   2: {
   3:     Recipe result = null;
   4:  
   5:     SqlParameter recipeIdParameter = new SqlParameter
   6:     {
   7:         ParameterName = "@RecipeId",
   8:         DbType = System.Data.DbType.Decimal,
   9:         Value = recipeId
  10:     };
  11:  
  12:     DbCommand cmd = this.CreateStoreCommand("SelectRecipeWithIngredients",
  13:         CommandType.StoredProcedure, recipeIdParameter);            
  14:             
  15:     // Use a connection scope to manage the lifetime of the connection
  16:     using(var connectionScope = cmd.Connection.CreateConnectionScope())
  17:     {
  18:         using(var reader = cmd.ExecuteReader())
  19:         {
  20:             // Materialize the recipe.
  21:             result = reader.Materialize<Recipe>().Bind(this.Recipes).FirstOrDefault();
  22:  
  23:             if(result != null)
  24:             {
  25:                 // Move on to the categories resultset and attach it to the recipe.
  26:                 // Also bind it to the datacontext, so the object tracking works correctly.
  27:                 reader.NextResult();
  28:                 result.Categories.Attach(reader.Materialize<Category>().Bind(this.Categories));
  29:  
  30:                 // Materialize the recipe ingredient information and attach it to the recipe.
  31:                 // Also bind it to the datacontext, so the object tracking works correctly.
  32:                 reader.NextResult();
  33:                 result.RecipeIngredients.Attach(reader.Materialize<RecipeIngredient>().Bind(this.RecipeIngredients));
  34:  
  35:                 // Materialize the ingredients and attach them to the datacontext to enable object tracking.
  36:                 reader.NextResult();
  37:                 var ingredients = reader.Materialize<Ingredient>().Bind(this.Ingredients);
  38:  
  39:                 // Iterate over the ingredient information 
  40:                 // and attach the ingredients to the records
  41:                 foreach(var item in result.RecipeIngredients)
  42:                 {
  43:                     // Attach the related ingredient to the ingredient reference property
  44:                     item.IngredientReference.Attach(ingredients.FirstOrDefault(
  45:                         ingredient => ingredient.IngredientId == item.IngredientId));
  46:                 }
  47:  
  48:                 reader.NextResult();
  49:                 var units = reader.Materialize<Unit>().Bind(this.Units);
  50:  
  51:                 // Iterate over the ingredients in the recipe and attach the related unit information
  52:                 foreach(var ingredient in result.RecipeIngredients.Select(item => item.Ingredient))
  53:                 {
  54:                     // Attach the related unit to the unit reference property
  55:                     ingredient.UnitReference.Attach(units.FirstOrDefault(unit => unit.UnitId == ingredient.UnitId));
  56:                 }
  57:             }
  58:         }
  59:     }
  60:  
  61:     return result;
  62: }
You can materialize a resultset by invoking the Materialize<T> method on the datareader. This will read the whole resultset and convert it into entities.
Although not required, it’s a good idea to bind the materialized entities to the ObjectContext. This enables the ObjectContext to perform object tracking on them, thus supporting update and delete scenarios. You can bind the entities using the Bind extension method to a specific EntitySet<T> object on the ObjectContext.
When you look at the previous code snippet, you will notice that I’m using a bunch of Attach calls. This is done so that I can link the child objects to their parents. You can use the Attach method on anEntitySet<T> object to attach multiple objects to it. Attaching two objects that are part of a many-to-one or a one-to-one relation is done by calling the Attach method on the …Reference properties that you can find on the various entities in your entity model.

THE END RESULT

When you execute the GetRecipeWithIngredients method you will end up with a complete object graph of a single recipe. In this case the “Chicken in the basket” recipe.
clip_image006

CONCLUSION

The combination stored procedures and the ADO.NET entity framework still isn’t a very happy marriage. Although it’s much better than with the previous version. There’s especially much to gain the field stored procedures that return multiple resultsets. It’s just too much work to write all the mapping code even with the help of the the Materialize<T> method.
At least I hope this post helps to give you an idea how you can use stored procedures that return multiple resultsets in combination with the ADO.NET entity framework.