czwartek, 11 marca 2010

Visual studio QuickReplace using Regular Exporession [Regex]

I don't have to persuade anybody that using regex saves a lot of time. Recently I was about to add 20 new parameters to the stored procedure updating record. The reason for that was the change in table definiton. I had to make following steps: 1) add new parameters to sp, 2) add this parameters to update statement 3) add this parameters to insert statement I could use copy and paste, because all three steps needed only some changes withing string with new columns. 1) The sample from input sql I had to write for sp Input params
@CategoryL3 nvarchar(50), @CategoryL4 nvarchar(50),
2) The sample from update statement
[CategoryL3]=@CategoryL3, [CategoryL4]=@CategoryL4,
3) The sample from insert statement
[CategoryL3], [CategoryL4] 
and then:
@CategoryL3, @CategoryL4 
Here is regex to find things from first sample:
[@]{.[^@ ]*} .[^@ ]*,
- in {} brackets we get the expression we want to extract from what has been found.
I'm looking for:
- @ at sing
- ".[^@ ]* "- all the signs (.*) until space (which is after star) that don't contain @ sign
- then there is space and anything thats between this space and comma, but again without @ sign (to avoid greedy results) .[^@ ]*


then in replace with text box I can put \1 which result with setting it to the values I enclosed with curly brackets.

wtorek, 9 marca 2010

Adding new parameter to WebReport (asp.net 2.0 sql server 2005)

The situation is as follows: we have existing WebReport which users stored procedure for getting data. We want to add new parameter. 1) Alter stored procedure to expect new paramter 2) In the layout tab in report designer go to menu Report => Report Parameters and add new parameter. Img. 1: CustomerIds - new parameter

Initially I thought it's enough, and you can imagine how supprised I was when trying to preview report I got an error: procedure expects parameter which was not supplied. I spend more than half an hour to figure out what caused my problem. There is third step you have to make when adding new param. 3) On dataset properties Parameter tab you have to enter the input parameter of the sp for 'name' and select report parameter under value. Img. 2: 3rd step.

That's it.

piątek, 5 marca 2010

dropdownlist has a SelectedValue which is invalid because it does not exist in the list of items

Enviroment: You've got a FormView or some other data control which displays single item and allows edit it. In edit mode there's a dropdown list with available names that user can select value from. Then when user wants to edit a person the underlaying data for selecting name has changed and has no more an item with value for edited person. (This can happen when for example someone deletes a name record directly in the db) That situation will cause "dropdownlist has a SelectedValue which is invalid because it does not exist in the list of items" error being thrown, because we've binded dropdownList.SelectedValue to an item which isn't in db any more. The workoround is to delete SelectedValue binding in aspx code and and handle unexpected situation in FormView_PreRender event. Here's a code for that:
protected void FormView1_PreRender(object sender, EventArgs e)
    {
        if (FormView1.CurrentMode == FormViewMode.Edit)
        {
            DataRowView rowView = (DataRowView)(FormView1.DataItem);
            DropDownList ddlNames = FormView1.FindControl("ddlNames") as DropDownList;
            bool isItemStillThere = ddlNames.Items.FindByValue(rowView["NameID"].ToString()) != null;
            if ((rowView != null) && isItemStillThere)
            {
                ddlNames.SelectedValue = rowView["NameID"].ToString();
            }
        }
    }
The aspx code:
 
Test website:

środa, 10 lutego 2010

Restoring Database in SQL Server 2005

This is quick tip explaining how to restore database in SQL Server 2005. The new database had different schema than the one I wanted to restore data to.
This is the sql Generated by Sql management studio:
RESTORE DATABASE [DatabaseName] 
FROM  DISK = N'C:\temp\db\DBBackup.bak' 
WITH  FILE = 1,  NOUNLOAD,  STATS = 10
GO

Unfortunately it running it couses an error: Error 3154: The backup set holds a backup of a database other than the existing database.
All you need to do is to add parameter REPLACE. this is how new query looks like:
RESTORE DATABASE [DatabaseName] 
FROM  DISK = N'C:\temp\db\DBBackup.bak' 
WITH  REPLACE, FILE = 1,  NOUNLOAD,  STATS = 10
GO

poniedziałek, 18 stycznia 2010

EntityFramework and many to many relation

Today I'm going to share my thoughts about many to many relationship, when working with EntityFramework. Let's assume that we have datatables like shown below:
As we can see in the picture we have many customers, that can have many projects, but when we make this association we would like to know save additional information about AmountSpent and PerComplete.
This kind of mapping in entity framework will result in 3 tables in entity datamodel, opposite to situattion when association table contains only references ids - then we have only two objects in entity datamodel. What's important you have to make primary key in mapping table as combination of referenced identifiers.

czwartek, 8 października 2009

Conversation (from Seam Framework) in ASP.NET MVC (Part 1)

Recently I faced a problem of implementing an conversation in ASP.NET.
The original I based on is explained here: http://docs.jboss.org/seam/2.2.0.GA/reference/en-US/html/conversations.html . To start with let's explain what conversation is. When users browses some of web pages, the context of all the way he went, an the conditions he chose will be saved in a context - conversation context. This context shouldn't depend on browser window, so i.e. opening web page in new browser window shouldn't break the conversation context.
To explain conversation in real world let's assume that user browses our page in such a way:
1) chooses product catalog
2) narrows product list by specifying some conditions (for example price, color)
3) views single product
4) shows product images.

All the way (this 4 steps) are a conversation. We can then show links in breadcrumb, so that user with one click, can come back from step 4 to step 1.
I assumed that if user goes back (by clicking on breadcrumb) all further steps will be forgotten.
There is my solution:
a) Firstly I created an attribute, that I will decorate all the actions, which I want to be placed In conversation context.
b) Add this attribute to some controller's actions.
c) Create an conversation manager, which will take care of managing conversations.
there can be a lot of conversations, each of it will be identified by parameter cid (conversation id) in requested url. d) Create an breadcrumb, which will take information about browsed pages both from Web.sitemap file and my conversation context.

ad.a)
Listing 1: Conversation Attribute implementation
    /// 
    /// Attribute adding Conversation context to actions
    /// 
    public class Conversation : ActionFilterAttribute, IActionFilter
    {
        HashSet _Types;

        public HashSet Types
        {
            get { return _Types; }
            set { _Types = value; }
        }


        public Conversation(params CType[] types)
        {
            _Types = new HashSet();
            foreach (var item in types)
            {
                _Types.Add(item);
            }
        }

        #region IActionFilter Members

        void IActionFilter.OnActionExecuted(ActionExecutedContext filterContext)
        {
            
        }

        /// 
        /// Called when [action executing]. Saves conversation context to session.
        /// 
        /// The filter context.
        void IActionFilter.OnActionExecuting(ActionExecutingContext filterContext)
        {
            ConversationManager cMgr = new ConversationManager(filterContext.HttpContext, Types);
        }

        #endregion
    }

As you can see this attribute will take in it's constructor list of CTypes (conversation types). This types will indicate if page begins conversation or if opening web page with different attributes will erase previous element in conversation context or will add new (if the local path of requested page is the same).
In line 37, when an actions is being executed I create an conversation manager which will take care of managing conversation.
Listing 2: Conversation Types enum
      
      /// Describes type of conversation
      /// 
      public enum CType
      {
          /// 
          /// Begins new conversation context
          /// 
          Begin,
          /// 
          /// Joins conversation for the same Requested action, but with new parameers
          /// 
          Join,       
      }

ad. b)
Listing 3: Example of using Conversation attribute:
[Conversation(CType.Begin, CType.Join)]  
    public ActionResult Index(SearchParams searchParameters)
    {
      // Your action code
      return View();
    }
This is an example of using Conversation attribute.
The rest of implementation will be placed in next post.

środa, 23 września 2009

ASP.NET MVC "Remember me" and FormsAuthentication timeout

Recently I came across a strange behavior of ASP FormsAuthentication class. As it is said in "Pro ASP.NET 3.5 in C# 2008" book forms authentication should create persistent cookie when user marks "Remember me" checkbox in login control. Persistent cookie should avoid logging off user when he closes browser or when default timeout passes (it is configured in forms authentication section in Web.Config file).
Listing 1: Web.Config - Forms authentication configuration
  
         
  

To avoid logging off user even if default timeout goes by I needed to edit SignIn method from FormsAuthenticationService class which is placed in AccountController.cs file.
Listing 2: Updated SignIn method
public void SignIn(string userName, bool createPersistentCookie)
{
    // Remember me was checked - set cookie to remember user for 10 days (or until he logs off)
    if (createPersistentCookie)
    {
        var tenDaysFromNow = DateTime.Now.AddDays(10);
        FormsAuthentication.Initialize();
        HttpCookie cookie = FormsAuthentication.GetAuthCookie(userName, createPersistentCookie);
        cookie.Expires = tenDaysFromNow;
        var cookieVal = FormsAuthentication.Decrypt(cookie.Value);
        FormsAuthenticationTicket at = new FormsAuthenticationTicket(cookieVal.Version, cookieVal.Name, cookieVal.IssueDate, tenDaysFromNow, true, cookieVal.UserData);
        cookie.Value = FormsAuthentication.Encrypt(at);
        HttpContext.Current.Response.Cookies.Add(cookie);                                              
    }            
    else
    {
        FormsAuthentication.SetAuthCookie(userName, createPersistentCookie);                 
    }            
}

The code grabs default authentication cookie (line 8), decrypts its value in line 10 and based on existing value creates new Authentication Ticket with updated ExpirationDate. In the end cookie has been added to response cookies collection.