Casting from a base class to a derived class
Today a friend of mine asked me how to cast from List<> to a custom MyCollection class, where MyCollection is derived from List<>. Is this possible?
Data integrity check using hashing
Mark a C# class data member as readonly when it’s read only
The readonly modifier is used to declare an instance-specific constant data member which can be initialized in the class constructor and is not limited to compiler-time constants only.
DataGridView: how to bind nested objects
Single Sign On across multiple ASP.NET applications
Machine Key
The machineKey element of the web.config file is used to specify keys for encryption and decryption of forms authentication cookies and view state data, and also when dealing with out of process session state.
The default configuration uses auto generated decryption key and validation key, and SHA1 encryption type.
Using the default configuration, different web applications have different decryption and validation key, since they are randomly generated. To force 2 applications to use the same keys, they must be explicitly defined in the web.config file
A complete description of the machineKey element is available here
Single Sign On
Single Sign On (SSO) is a term used to indicate when a pool of applications need a centralized authentication, so that users login once and access to any application.
Implementing a single sign on is quite simple, and can be done by configuring the applications using the web.config file.
A default configuration for forms authentication is defined as follows:
<configuration>
...
<system.web>
...
<authentication mode="Forms">
<forms name=".cookiename"
loginUrl="~/Login.aspx"
timeout="30"
path="/" />
</authentication>
...
</system.web>
...
</configuration>
Form Authentication
Forms Authentication uses an authentication ticket stored in either a cookie or embedded in the url.
When used in cookie mode, the cookie contains authentication data, encrypted so that data can be read by the application who has created the cookie.
Cookies are associated to 2nd level domains (example.com), and can be accessed from any 3rd level domain (www.example.com, test.example.com, and so on).
where .cookiename, by default, is .ASPXFORMSAUTH.
In order for authentication data to be recognized across multiple applications, each application must be configured to use the same values for cookie name, protection and path attributes. But this isn't enough - in fact, they must also have the same machine key values (see the side box for more info about the machineKey element). These information are used to encrypt the forms authentication cookie, as mentioned in the "Forms Authentication" side box.
Below a sample web.config excerpt which must be added to each application we want single sign on enabled. In this sample, the validationKey and encryptionKey attributes must be replaced with unique values you have to generate for your applications pool.
<configuration>
...
<system.web>
...
<authentication mode="Forms">
<forms name=".cookiename"
loginUrl="~/Login.aspx"
timeout="30"
path="/"
/>
</authentication>
...
<machineKey
validationKey=
"F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902"
encryptionKey=
"F9D1A2D3E1D3E2F7B3D9F90FF3965ABDAC304902F8D923AC"
validation="SHA1"
/>
...
</system.web>
...
</configuration>
Second and third level domains
If the cooperating applications are installed under the same 2nd and 3rd level domain, but on different virtual folders, then no additional code is required.
If applications are installed on different second level domains (www.domain1.com and www.domain2.com), the SSO method described in this article won't work, since cookies cannot be read by applications under different second level domains. For example, if application A in domain1.com issues a cookie, the cookie may be read by A itself and any application hosted under www.domain1.com and any other 3rd level domain (test.domain1.com, beta.domain1.com, and so on). Application B in domain2.com isn't able to read the cookie, since it is hosted under a different second level domain.
If cooperating applications are installed on different third level domains, then we need to add some code in order to make SSO work. The code simply has to add the domain name to the authentication cookie, as outlined below
protected void Login (string strUserName, ...)
{
...
System.Web.HttpCookie cookie;
cookie = FormsAuthentication.GetAuthCookie(strUserName, False);
cookie.Domain = "domain1.com";
cookie.Expires = DateTime.Now.AddDays (-1);
Response.AppendCookie (cookie);
...
}
Cookie Expiration
If different applications set different cookie expirations, the actual expiration value is the one set by the application which issued it. So if application A is configured to set an expiration of 1 hour and application B 2 hours, and the user signs in using application B, then the cookie expiration is set to 2 hours.
Logging out
Usually, in order to log out a user, a call to the Authentication.SignOut() method is used - this isn't enough when using SSO. In order to perform a single sign out, the quickest way is to set the cookie expiration to a past date - this ensures that the cookie won't be used by any application for authentication.
protected void Logout (string strUserName)
{
System.Web.HttpCookie cookie;
cookie = FormsAuthentication.GetAuthCookie(strUserName, false);
cookie.Domain = "domain1.com";
cookie.Expires = DateTime.Now.AddDays (-1);
Response.AppendCookie (cookie);
}
Integrating Web Applications
What said so far is valid if applications use the same database to store user profiles. But what if 2 applications use each one their own database?
In this case, the SSO works, but sooner or later one of the applications will throw exceptions due to missing data in its database. If a user registers in application A, once he signs in he can access to application B - but he never registered in application B, so application B doesn't have this user in its database.
This is the case when, for example, we have to integrate 2 existing applications, which already have their own authentication and registration implemented.
To solve this problem, we have 2 choices:
- modify both application in order to use a single authentication and registration process, and having a shared user profile repository
- choose one application as the master application, and remove the authentication and registration process from the other application (the slave application)
We'll focus on the second solution.
This method requires that the database used by slave applications is accessible by the master application. This can be achieved by either:
- Create a single database which holds both application databases. In this case it would be good to use different prefixes for database entities to avoid naming conflicts - this could happen if both databases have a Users table. If we choose mst and slv as prefixes, we should rename the Users table to mst_Users for the master database and slv_Users for the slave database. This requires that we modify the source code and stored procedures.
- Use 2 different databases, but the master application must be able to access to the slave's database.
Authentication should be performed in the following way:
- The user accesses to the master application, and signs in
- The master application verifies the user's credentials
- The master application verifies whether the logged user is defined in the slave database - if not, accesses to the slave's database and creates the new user
- The master application calls (if existing) a slave's stored procedure which performs post-authentication processing (such as setting a "logged in" field, inserting a new row in a history table, and so on)
- The master application generates the SSO cookie
User profile creation on the slave database requires that:
- the master application is able to access to the slave's database
- the slave's database exposes a stored procedure which handles user registration (we may need to write it by ourselves)
The second requirement isn't mandatory, since it could also be achieved by using inline SQL - but I usually prefer the stored procedure solution.
Final touch
There would be a few final things to do on the slave application:
- Removal of all login links
- Replacement of logout links with a "Back to the Master application" link
- Replacement of all "User's profile" links to point to the master application user's profile page
These steps ensure that navigation is consistent with integration - we're supposing that all user's info (credentials, profile, user's preferences) are handled by the master application, so we need to modify the slave application accordingly. It is responsibility of the master application to update user's profile in the slave application.
What if different cookies are used?
There may be cases where we want to keep authentication cookies separated from master and slaves applications. In this case we can't share the authentication cookie among cooperating applications.
In this case the solution is to create an authentication cookie for the slave application from within the master application.
The code below creates an authentication cookie from the slave application:
FormsAuthenticationTicket ticket;
HttpCookie cookie;
string cookiestr;
ticket = new FormsAuthenticationTicket(
1,
userId,
DateTime.Now,
DateTime.Now.AddYears (120),
true,
"User Data",
"cookie_path"
);
cookiestr = FormsAuthentication.Encrypt(ticket);
cookie = new HttpCookie("cookie_name", cookiestr);
cookie.Expires = ticket.Expiration;
cookie.Path = "cookie_path";
Response.Cookies.Add(cookie);
Forms Authentication Ticket
The FormsAuthenticationTicket class is used to create and read the values of a forms authentication cookie identifying an authenticated user.
Forms authentication tickets must be encrypted using the FormsAuthentication.Encrypt() method before being issued as a cookie.
More information about the FormsAuthenticationTicket class can be found here.
The FormsAuthenticationTicket, as its name says, is a class used to generate authentication tickets (see the side box for more details). The code sample above shows that the following parameters are used to create the ticket:
- ticket version number
- user id
- date and time at which the ticket was generated
- ticket expiration
- whether creating a persistent cookie or limited to the current browser's session
- user specific data to be stored in the ticket (for example, this could be a user class)
- cookie path
References
How to better appreciate your most preferred language
The universal technology
I've seen a lot of developers telling that Linux is better than Windows, C# is better than Java, Delphi is better than VC++, and so on. But if you ask them if they know the other language they are comparing with, they say no.
I was one of them, since I believed that the best IDE was Delphi, the best platform was Windows, and the best language was C++. At least, until I started working on "real projects" and not on applications made just for fun. When I had to learn Java and use it to develop server applications on Sun platforms, I started to appreciate the language and the Unix-like environments.... and I started to believe that these technologies were better than those I thought were the best. Soon I realized that every technology is the best, depending on where it is applied.
There is no universal technology or language which solves all problems
Now I don't believe anymore that there is the universal technology or language which solves all problems. Every time I start a new project, if the customer doesn't have a specific preference, I always spend some time trying to understand what are the best tools to implement the project - and the result depends from the project itself. In web development my favorite preference is the .NET technology, for several reasons - but this is not a choice that can be done every time for every project. For example, if one of the requirements is that the application must run on open source environments, .NET wouldn’t be the proper choice.
The proper tools
During my professional experience I've tried to learn as many languages as possible. If I get confident knowledge of each language, I'm able to choose the best solution for every problem, from both the developer point of view (how simple or hard is the development using a specific language) as well as from the customer/project point of view (what are the benefits if I choose a technology instead of another). When I learned Java, I appreciated how life is easier with a memory manager which automatically disposes objects no longer referenced. When I learned C#, I appreciated the integration with the .NET technology, the foreach statement, but I also noticed how exception handling was better in Java, since exceptions must be explicitly handled within each method or the method itself must be declared to throw those exceptions which aren't handled in its body. I also, and still, like the C++ philosophy: "The developer always knows what he's doing". This is the reason why C++ offers more power with pointers and access to memory. It's irrelevant that it's not always true the developer always knows what he is doing :-) The key point is that you have the power to do almost everything, although at a price (usually more attention when dealing with pointers and dynamically allocated memory, and more debugging....)
PHP Revolution
Lately I've appreciated a language I've used in the past, and which I didn't like: PHP. The reason why I don't like PHP is that I prefer strongly typed variables, variable declarations, as well as to know from the compiler if I wrote something wrong in my code, such as the name of a variable (a common mistake in PHP which leads to unpredictable results) or a function call (which usually leads to a run-time error). But I have to say that it's extremely practical the ability to save your PHP code and test it immediately without the need of recompilation, deployment, etc. - a perfect solution for the project I'm currently working on. And I wouldn't had chosen it if the customer hadn't explicitly asked for it. We never stop learning!! Now I'll definitively choose it again in the future, if the prerequisites for its usage are good, and the project will benefit from its usage.
Can I say that C# is better than Java?
Yes and no. It depends. As outlined above, in order to state that a language or technology is better than another, I need to:
- have proficient knowledge of both
- compare pro and cons applied to a specific project
But the result of the comparison is limited to the project - on a different project, the choice could be different:
- if I need to care about speed, maybe the best solution would be C++, but not for web applications
- if I need portability, Java is best - but I wouldn't choose it if the application has a user interface
- if I need modularity and easy of development on a web application, my choice would fall on ASP.NET
- if I need low licenses cost, the choice could be PHP, Java/JSP, or Ruby On Rails
Your opinion
How do you choose the technologies and languages on your projects? Do you focus on a single technology, and use others only when the customer explicitly asks for them?
Tags
- android (1)
- appengine (1)
- asp.net (1)
- C# (6)
- codecharge studio (1)
- development (1)
- dojo/dijit (1)
- java (2)
- javascript (1)
- learning (1)
- PHP (3)
- RSS/Atom (1)
- sso (1)
- vs.net (1)
- webdesign (1)
- windowsmobile (1)
- WinForms (1)