Tuesday, November 12, 2013

Update External Control outside of ASPxGridView (DevXPress)

It's impossible to update external control rendering during the ASPxGridView callback.

To send data from Server side callback event to Client side (JS),  you can use the "JSProperty"
 http://www.devexpress.com/Support/Center/Example/Details/E2379

e.g
C#:
    myGridView.JSProperties("cp1")="test value"; 
[JScript]
   EndCallback="function(s, e) {
       if (s.cp1) {
           alert(s.cp1);
           delete s.cp1;
         }
   } 
The other solution to update the external control in the server side event, you need 
disable the callback by setting the EnableCallBack property of the grid to "false" 

ASPX
 <dxwgv:ASPxGridView ID="grView1" runat="server" KeyFieldName="ID"
 OnCustomButtonCallback="grid_CustomButtonCallback"  EnableCallBacks="false" >

C#
 protected void grid_CustomButtonCallback(object sender,
              ASPxGridViewCustomButtonCallbackEventArgs e)
        {
            if (e.ButtonID != "edit") return;
            txt1.text = grView1.GetRowValues(e.VisibleIndex, "ID").ToString();
        }



References:
http://www.devexpress.com/Support/Center/Question/Details/Q405422
http://www.devexpress.com/Support/Center/Question/Details/Q349498

Tuesday, October 15, 2013

Javascript add validation error

To highlight or show the validation error on control using Javascript

$("#objID").addClass('input-validation-error');

Remove the validation error:
$("#objID").removeClass('input-validation-error');

Tuesday, August 13, 2013

FileStream in SQL Server



Step 1: Enable File Stream in SqlServer Configuration Manager
1.       Right click on the Server that you want to enable file stream  -> Properties
2.       Check the enable filestream checkboxes


Step2 : In the SQLServer Management Studio
1.       Enable filestream by running below command
EXEC sp_configure filestream_access_level, 2
RECONFIGURE
Go

2.       Add File Group to the DB
ALTER DATABASE [Your_Database_Name]
ADD FILEGROUP [Your_FileGroup_Name]
CONTAINS FILESTREAM
Go

3.       Add file directory to the filegroup
ALTER DATABASE [Your_Database_Name]
ADD FILE
(NAME=Your_FileStreamName,
 FILENAME='E:\FileStreamDir'
 )
TO FILEGROUP [Your_Database_Name]
Go

Note: to check the filestream access level your Sql Server

SELECT * FROM sys.configurations
WHERE name = 'filestream access level'
The “value in use” means:
  • 0 = Disables FILESTREAM support for this instance.
  • 1 = Enables FILESTREAM for Transact-SQL access.
  • 2 = Enables FILESTREAM for Transact-SQL and Win32 streaming access.
Step3 : Create table that contains FileStream column
The  table that has filestream column must contain a uniqueIdentifier ROWGUIDCOL.
The File Stream column is defined as Varbinary (Max).
Use [Your_Database_Name];
Go
CREATE TABLE [dbo].[TblDocuments]
([Id] [uniqueidentifier]  ROWGUIDCOL DEFAULT NEWID() NOT NULL UNIQUE,
 [DocNumber] nvarchar(30)  PRIMARY KEY CLUSTERED,
 [FileName] nvarchar(300),
 [Description] nvarchar(300) ,
 [DocFile] [varbinary] (max) Filestream not null
 )
 ON [PRIMARY]
 Go

Step 4 : Insert data to the filestream table
insert into TblDocuments (Id, DocNumber, Description, DocFile, FileName)
values (NEWID(),
        'F001', 'test filestream'
        CAST('Just a string' AS VARBINARY(MAX)),test.pdf)


APPLICATION WITH FILESTREAM

To save file contents to filestream from .Net application, you just convert your file to Byte[] and can insert by Sql or any appropriate method.
byte[] bytes = System.IO.File.ReadAllBytes(Myfile.FullName);


Read filestream & write to a file in .NET

public class Document
{
 public string FilePath { get; set; }
 public byte[] ObjContext { get; set; }
 public string FileName { get; set; }

 }

public void ReadFileStreamAndWriteToFile()
        {
               
                string ConnectionString = Settings.GetConnectionString("main");
                DataContext context = CreateContext(ConnectionString);
                context.Connection.Open();
               
                // File_dest needs to be modified to a directory you have access to.
                string file_loc = @"E:\\Temp\\";

                DirectoryInfo folder = new DirectoryInfo(file_dest);
               
                using (new TransactionScope(TransactionScopeOption.RequiresNew))
                {
                    var result = context.ExecuteQuery(typeof(Document), "SELECT [DocFile].PathName() FilePath,  GET_FILESTREAM_TRANSACTION_CONTEXT() ObjContext, " +" FileName FROM [TblDocuments] where DocNumber=’F001'");
                                      
                    foreach (Document doc in result)
                    {
                        byte[] objContext = doc.ObjContext;
                        string filepath = doc.FilePath;

  SqlFileStream sfs = new SqlFileStream(filepath, objContext, System.IO.FileAccess.Read);

                        byte[] buffer = new byte[(int)sfs.Length];
                        sfs.Read(buffer, 0, buffer.Length);
                        sfs.Close();

System.IO.FileStream fs = new System.IO.FileStream(file_loc + doc.FileName, FileMode.Create, FileAccess.Write, FileShare.Write);

                        fs.Write(buffer, 0, buffer.Length);
                        fs.Flush();
                        fs.Close();
                    
                    }

                }           
              
               
        }

  private static WetaDataContext CreateContext(string connectionString)
        {
            return new CustomWetaDataContext(connectionString)
            {
                DeferredLoadingEnabled = true,
                CommandTimeout = Settings.GetOptionalSetting("SqlCommandTimeout").AsInt(60)
            };
        }
Notes:
1.       If you have problem in creating filestream on any directory of your PC
--->Check and make sure the log in user of Sql Server service has full access to the filestream location
2.       If you have problem in reading filestream from the application:
--->The user used to connect to the Sql Server from the .NET application should have Administrator privilege on the PC and has access to the file stream directory.

<connectionStrings>
<add connectionString="Server=localhost;Database=Your_DB_Name;User ID=test_user;Password=test123;integrated security=true" name="main" />
</connectionStrings>
** “test_user” should be the Window or Domain user with full access to the filestream directory AND can log in to the Sql Server.

3.       To read data from filestream in .NET, you must use transaction scope. Otherwise, GET_FILESTREAM_TRANSACTION_CONTEXT() will return null.

Wednesday, July 17, 2013

AJAX File Upload in MVC using IFrame

As you may aware via google, the Javascript cannot handle the File content. You cannot submit the File by using Ajax.
There are many solutions and plugIn both free and commercial on the Internet. But those seem not meet to my requirements. What I need is a synchronous upload the file and temporary store in object and display on the screen.

Therefore, the best solution is to use hidden IFrame recommended by many people. I just modify and simplify it to meet my requirements.

The result of below code:


The concepts are:
- Create a normal form for submitting file content with "enctype='multipart/form-data'" , and its target attribute is the IFrame ==> when the form is submit only the IFrame is refreshed (user will not aware of it)
- Handle the IFrame load function, to generate the result on the Partial view

Step 1:  I have a model class PostImageFile











Step 2: In the View

We have Form (file and button), Partial view, and the hidden IFrame.



And we have the script when the "SubmitImage" button is clicked:
-  checked if use has select any file
- Submit the form ==> the action "AttachImage" (in the "Post" controller defined in the Form action) will  executed
- The target of the form is the IFrame ==> after the "AttachImage" is executed, the IFrame will reload
- Thus, script in the $("#iFrameImage").load will run. It will invoke "RefreshImagePartialView" action in the "Post" controller


Step 3: The Partial View

"GetImage" is a action in "Post" controller to render image from byte array.


Step 4: Controller
Now, let take a look in the Post controller.

- AttachImage : get the HttpPostedFileBase from the form and it's converted to Byte Array and stored in the TempData.

- RefreshImagePartialView: is called when the IFram is reload in order to refresh the partial view. It get the list of images from TempData and return to the partial view.

- GetImage: is called in the partial view to render image from the byte array. I used the combination of PostDate and FileName as the key for retrieving the byte array.


Friday, July 5, 2013

SQL Server 2008 login Error: returns 233 or 18456 error codes

Failed to log in SQL Server by using "sa" account.

The error code was 18456 which meant wrong password. But, I did input the right password. (If you are not sure about the password of "sa" , log in as any account which has "SysAdmin" role and change the password for "sa").

Sometimes, I got the error 233 which related to the client protocol. Based on the search results on google, I changed the order of client protocol in Sql Server Configuration Manager by setting TCP/IP before the NamedPipes.

But the above 2 solutions don't solve the problem. Actually, because the "Server Authentication" mode was set to "Window Authentication mode" only, that's why "sa" cannot log in.
So, after changing the authentication mode to "Sql Server and Windows Authentication" mode, it works fine.




Friday, June 28, 2013

Placeholder for Help Text

Since the placeholder (help text) feature of HTML 5 is supported by IE, we can create our own help text by using jQuery.

Assumed that on the .cshtml page, we have a TextArea control with ID ="Description".

Step 1: Set the help text to the control, and set the text color to grey
  var promp = " Please enter description here...";
    $("#Description").text(promp);
    $("#Description").css("color", "grey");

Step 2: Set cursor to the first position when the control get focus
     //SET CURSOR POSITION
        $.fn.setCursorPosition = function (pos) {
            this.each(function (index, elem) {
                if (elem.setSelectionRange) {
                    elem.setSelectionRange(pos, pos);
                } else if (elem.createTextRange) {
                    var range = elem.createTextRange();
                    range.collapse(true);
                    range.moveEnd('character', pos);
                    range.moveStart('character', pos);
                    range.select();
                }
            });
            return this;
        };

        $("#Description").on('focus', function () {
            $("#Description").setCursorPosition(0);
        });

Step 3: Clear the help text and reset text color to black, when user clicks on the control or presses key.

       $("#Description").one('keydown',function () {
            $("#Description").text("");
            $("#Description").css("color", "black");                   

        });

        $("#Description").one('click', function () {
            $("#Description").text("");
            $("#Description").css("color", "black");
        });

Step 4: It's very important to clean the help text when the form is submit or to check if user has input new text (if the field is set to require). In this case, we assume that the field is a required field. So, when user clicks Submit button, the below script will perform:

<script type="text/javascript">
   
    $(document).ready(function () {
     
         var promp = " Please enter description here...";
       
          $("form").submit(function () {
                      
            if ($("#Description").text() == promp) {
                $("input[type=submit]").removeAttr("disabled");
                alert("Please enter description");
                $("#Description").focus();
                return false;
            }         
            return true;       
                         
           });
    });


</script>

Wednesday, May 22, 2013

MVC- Moq with UnitOfWork (using Ninject IoC Container)

This article will introduce:
- how to create a generic repository and using UnitofWork 
- how to use Ninject to inject context into controller
- how to perform unit test with Moq on the UnitOfWork using generic repository


Prerequisite: get below package from NuGet
- Moq
- Ninject

In this example, I will use Product and Category models.

Step1 : Create model class

Step 2: Create Db Context

In Web.Config, configure the default connection string. In my case, I set the "Initial Catalog=MvcRepository" in the connection string.

Create a "ProductDBContext" class referenced from DbContext


 Step 3: Create Generic Repository Interface


To understand more about constraint on type parameters, view here

Step 4: Create Repository Class

The repository class will implement the IRepository interface.
Repository class has two generic parameters: TEntity, and TContext.
The purpose of adding TContext is to enable the repository class used by different DbContext.

Step 5: Create the Product and Category Interface and Repository

- The interface is created for each model. In each interface, you can add any required functions for specific purpose.
- Each repository class of each model will implement the new interface of the model. And all of the classes inherit from the Repository class (which implemented the IRepository interface).

- In the "ProductRepository" class below, we pass the "Product" class as the TEntity to repository. And keep the TContext as the generic param (this param will be passed from the unitofwork, unit test, or any controller/ class that invoke ProductRepository).







 Step 6: Create UnitOfWork

 Using UnitOfWork is to ensure that all the DbSets are saved at the same time (in case you need to update more than one table/ dbSet in the transaction).

In this example, I will use UnitOfWork to wrap the Product and Category repositories.
First, create an interface for unitofwork. The interface implements the IDisposable interface. The "SaveChange()" method is for saving data to the context.



Next, create a UnitOfWork class to implement the IUnitOfWork interface. Now, the "ProductDbContext" is used and passed to the Product and Category repositories.

Step 7: Using UnitOfWork in Controller

Create Product controller by using scaffold and replace the origional code by using UnitOfWork.
We inject the UnitOfWork to the controller via constructor. This constructor is used for passing the context from unit test.

Note: if you run the application now, you will get error. Because, MVC needs a parameterless constructor. We are going to manage this by using Ninject in next step.


Step 8: Ninject IoC

After installing Ninject from NuGet, you should get "NinjectWebCommon.cs" in the App_Start directory.
In the "RegisterServices" method, bind the UnitWork to IUnitWork. This statement tells the system that when the contoller is looking for IUnitOfWork, it will pass UnitOfWork.



Now, the application should be successfully built and work as normal.
We have completed the application by using generic repository, unitofwork, and Ninject.
Next step, we will see how we can perform unit test with the generic repository.

Step 9: Unit Test