translating the .resx files to another language does not require any programming knowledge at all

Translating a properly globalized site in asp.net is simple and does not require the least bit of development knowledge... which is good,
because most developers I know barely have a grasp on their own [non-programming] language.
This post should probably come after one on how to globalize your asp.net site, but I have an urgent need to explain how to do this first
(someone has volunteered to translate my open-source project Slick-Ticket to Spanish; thanks Victor!).

how does it work?

First of all, you should understand how this actually works, it may make it easier.
Every page in a site has access to two types of resources (when I say resources here I am referring to strings, words or phrases): Global Resources, and Local Resources - these resources are held in .resx files.
Global Resources are commonly used resources that all pages can see, and Local Resources are resources that only a specific page can see.
Each language/dialect has a specific code, which you can see here: Language Codes (you can see your default setting in your browser options, for IE, check Tools->Internet Options->Languages).
Each page then has place-holders where it will substitute a specific language's resource if it is available.
For example, if your browser's settings are set to Mexican Spanish (es-mx) and you are trying to view example.aspx, asp.net will look for the example.aspx.es-mx.resx file to fill in the text.
If that file is not present, it will default back down to the default resx file which is example.aspx.resx.

Once you have your editor, just go through and edit the column to be translated, and *ONLY* that one column, messing with the key/name field will break the translation completely.

folder structure

This is the only part that might be a bit confusing.
Each folder that contains .aspx, .ascx, etc. files (files with words to be translated) will have their own App_LocalResources folder, and in this folder, there will be a corresponding *.aspx.resx file for each file.
Also, any additional languages will be held in a folder with the language abbreviation, and a corresponding file for each file as well.
For example, in the admin folder shown here, you can see that it has it's own App_LocalResources folder, in that folder is each corresponding default (in blue) .resx file and there is a folder for each additional language.
Here you see the en-us folder (English - United States) and in that you see the same .resx file, but each is named *.en-us.resx (in red) instead of just *.resx.
This is the same for each folder, so you will see many App_LocalResources folders.
If you forget to change any of them, it will be pretty apparent when you run the program and a lot of stuff does not match up.

Then there is the App_GlobalResources folder in the root;
the same thing applies here, just do the same and translate the value column.

Remember that asp.net will first look for your desired language, and use it if it is there, if not, it will drop down to the default.

a couple notes

A couple things to keep in mind, if you see any html markup (not the best practice, but sometimes necessary), remember this:

<do_not_edit>edit_this</do_not_edit>

Also, if you see brackets with a number in them (i.e. {0}, {2}, etc.), be sure to leave those, the developer is using that as a word placeholder.

that's it

Now, as long as it is available, your users will see your site in their preferred language.
It is a bit tedious to translate, but much easier than walking through the markup and screwing things up that way.
Also, if a resx file is ever missing, it will not error out, it will simply use the default for any parts that are not available.

PDFs are a very ubiquitous and useful file type, but they can be a pain to work with programatically

PDFs are extensively used in my organization, and people always want programs that will extract information from them.
It can be very difficult to get the information they want due to the strange format, but sometimes it's a necessity.
Here is how to get a PDF into text, from there you are on your own!

download the necessary files

There are always more than one way to skin a cat when it comes to programming, but the easiest way I have found for PDFs is to use the fantastic, open-source project
PDFBox. The download is good for all sorts of platforms, but you only need a few parts to use it with Asp.Net and C#.

*Now keep in mind the version numbers I show here may change, but the process should stay the same.

what you need

Just a few things, pull the following files into your bin:

FontBox-0.1.0-dev.dll

IKVM.GNU.Classpath.dll

IKVM.Runtime.dll

PDFBox-0.7.3.dll

Now just make sure you add a couple references in your project, it is a bit of a
strange process, so follow it closely. First, add this reference:

IKVM.GNU.Classpath

Then build the project, as the next reference requires the previous to be built.
So you then add this reference:

PDFBox-0.7.3

Then build again - once again, there may be a better way to do this, but this
is what the documentation said and it worked, so I won't mess with it.
Now all you need to do is make sure you add the following using statements to any code file that needs to use the parser:

using org.pdfbox.pdmodel;
using org.pdfbox.util;

all set, now use it

This quick snippet shows how to use the program to take in a pdf file and output it to a .txt file.
The inputs are simply the string 'pdf_in' which is the path to a PDF to
parse, and the string 'txt_out' which is the path to the output text
file.
You can easily modify it to take in a Stream of some sort or something else like using a FileUpload or output some other way, but this should get the idea across.

And there you have it, your PDF is now a (most likely, ugly and difficult to parse) text file with your PDF data in it;
now it's up to you to figure out how to use it.
As you will see, PDFs can (not always) be very strange in how they come out as text, tables will often be in odd order and such and it is a new adventure each time to engineer an effective and acurate parsing scheme that is very case-specific.
Normally I would offer a download, but these files are pretty big, so I will leave it to the guys at SourceForge.

Add a new item into the table and database and have it immediately sortable, pageable, etc without any postback

This is probably the hardest part about a full CRUD (Create, Read, Update, Delete) system, but as we have already covered 'RUD', it's time to hit the 'C'.
First of all, we have to break down what will be happening, both on the client-side, and the server side, then it will be easier to dissect.

User pulls up a 'New Entry' dialogue (client)

User enters information and it is validated (client*)

Valid information is sent to the server (client)

Server attempts to add in new item (server)

Server spits back status update (server)

status update is displayed (client)

item is added into the visible table (client)

input fields are cleared and the input dialogue is hidden (client)

The * above denotes that while in this example we are doing only client-side validation, it is in your best interest to add in some server side as well
(keep in mind that this example will not work without javascript, so it is not robust and does not 'gracefully' degrade).

As you can see, most of the heavy lifting here is done on the client side, with the dedicated server doing just a couple things.

set up the entry dialogue

First I am adding a couple divs which will be clicked to open the dialogue:

To go with the whole ajax feel, I am setting up the entry in a modal popup;
you probably noticed the class 'triggerNew' which isn't really a css class, but it will be used to by jQuery to hook into any elements that have that class and tie them to the modal.
To do that first we must include the jquery.jqModal plugin (which IMO is the best modal plugin as it is minimalist and customizable as well as easy to use)
in our masterpage.
demo.master

Now there is a lot going on there.
First of all, I used the Asp.Net validators as we are most familiar with them, and
they play nicely with jQuery.
Also, I am not using asp:TextBoxes at all, I am sticking with the basic input boxes.
But, because I am using the Asp.Net Validators, I still need to include runat="server" with each input that I Validate;
this also means that they will get weird Asp.Net IDs and not the exact ones I
assign them.
All I am doing here is making sure all the fields have values, and that age is a diget with 1-3 digits (yes, someone can be 999 in this system...).

In addition, the css class 'jqmClose' class is included in a link: this will automatically be assigned to close the modal window by jqModal.

I also put an additional 'working' element in there so the user can see that dialogue while the program is running its magic.

But as it stands now, we can't even see that popup, get the validators to fire or submit any sort of data.
Here comes the jQuery.

work the jQuery magic

Here is the script, it is explained in the comments:

//assign all 'triggerNew' elements to open the modal dialogue
$('#new').jqm({ trigger: false }).jqmAddTrigger($('.triggerNew'));
//attach this event to the clicking of the 'submit' div
$("#submit").click(function() {
//will not do anything if the validators don't check out
//Page_ClientValidate('ValidationGroup') is an Asp.Net generated function
if (!Page_ClientValidate('new')) { return false; }
else {
// get the values from the textboxes into an array
// notice that this is using .ClientID to get the strange Asp.Net ID assigned to it
var vals = [
$("#<%= txtFirst.ClientID %>"),
$("#<%= txtLast.ClientID %>"),
$("#<%= txtAge.ClientID %>")
];
// do the ajax post
$.post(
//function is at
"ajax_functions/insert.aspx",
//send the values frorm the vals object
{ first: vals[0].val(), last: vals[1].val(), age: vals[2].val() },
function(data) {
//output the return data
$("#report").html(data);
// the class 'success' was sent back if it worked...
var success = (data.toString().substring(12, 19) == "success");
//add the new data into the table so the user can see it if it was successful
if (success) {
oTable.fnAddData([
vals[0].val(),
vals[1].val(),
vals[2].val(),
'&nbsp;'
]);
//clear the textboxes
$(vals).each(function() { $(this).val('') });
}
//hide the modal now that it's done
$('#new').jqmHide();
}
);
}
});

Note that this will not allowed items added since the last postback to be deleted/edited, that is why the last cell simpy gets an '&nbsp;'.
Keep in mind that it is possible, just beyond the scope of this tutorial.

Also, in a ghetto form of error reporting, I passed the css class which will
either be 'error' on error, or 'success' otherwise. We can use that to
decide whether or not to post the new data into the table and to clear the
inputs. This will catch any errors that we did not already account for.

Really all that remains is the server-side part, we need to make the page that is called: "ajax_functions/insert.aspx" to handle the inputs passed.

server-side functions

Notice this time that we used a $.post() method, which sends the stated values and returns something - in this case, we are having it return a chunk of html which will tell us what happened with the server, and it will be pushed into the 'report' div.
Here is our server operations:

As usual, this is the easy part. Now you have a full working CRUD system, with some pretty good error catching as such with absolutely no postbacks!
Ajax is fun and can be quite useful, I hope these tutorials helped make it a little more accessible to some Asp.Net devs, I know I learned a lot making them.

Delete an entry from the DB and remove the corresponding row from the table; plus an ajax loading indicator

GridView has an incredibly easy 'Delete' feature when used in conjunction with a DataSource, the problem is, that is requires a postback.
Since we are going the ajax route, this is a no-go.
Alternatively, we could wrap in in an UpdatePanel, but that is exactly what we are trying to avoid.
Deleting is very easy, we use a lot of the same methods that were involved in fixing the sort on
the last post
and using the jQuery .ajax() method.

changes to the markup

First we have to add another column for deleting and stick a delete image in there, this is simple enough.
I added unique ids to each row and each delete cell for jQuery to have something to hook on to, you could also add classes.
The markup hasn't changed all too much:

We put the id on the cell itself and not the image because it will be easier to grab with dataTables, not to mention easier to click.

now for the js

First of all, you will notice if we leave the .dataTables() call the same as before, you can now 'sort' by the last column (the delete column), that isn't right, we have to pass some parameters to our 'dataTables()' method to make sure that column gets ignored:

Also notice that we decided to store the resulting table in 'oTable' just like the last lesson.
Remember that this is because the sortable data is not kept in the table itself, but in an associated array, which we will need later.

Now, using the same method as last time, we will grab the position of the clicked item, attempt the ajax call, but instead of changing a value, we will delete a row.
Normally, deleting a row in ajax is very simple, you grab the row by the id, and do a hide() or slideUp(), etc. - but that will not totally work here.
Sure it would function, but since we are using sizing and paging, they wouldn't reflect the changes:
if you had 30 items in your table, and you were 'showing 10 of 30' items, and you deleted one the normal way, it would still say 'showing 10 of 30 items' when in fact, you are only now showing 9 of 29 items, and the problem then just compounds.
The brilliant minds who wrote the dataTables plugin built in ways to get around this.

First thing, we get the position of the clicked item (which all have 'del_' as an id prefix) and store that:

var pos = oTable.fnGetPosition(this);

As well as the id of the cell as we need the corresponding 'person_id' that is contained there:

And that is where the magic happens.
It was indicated that this was of type 'POST', the url that it is sent to (we
will get to that in a moment), and the POST query that was sent (the delete
cell's id, minus the 'del_' prefix). Then, on success, we simply output some feedback to the user into a new div with the id of 'report' - nothing special there.
But on the next line, we use the 'oTable' that we stored earlier that has all of the sortable data, and call the included function 'fnDeleteRow' with the position that we collected earlier, and that is what deletes the row.
The finished javascript looks like this:

This code is pretty simple.
Since we specified the POST in the ajax() call in jQuery, we knew the first element of the POST was going to be the person_id, and that is used to delete it from the DB.*NOTE* that I used a Thread.Sleep() in there which I NEVER recommend using.
it is just there to illustrate the ajax loading indicator that was implemented into the masterpage,
which is covered next.

ajax loading indicator

I snuck a new div into the masterpage with the id of 'working' and bound it to all jQuery ajax events with the following js:
demo.master

Also, you will notice that the CSS changed a bit, that is because this plugin has a hover property that resets the backgorund of the td, and that gave a funky interface;
now this can be taken care of with some jQuery magic pretty easily, but that is outside the scope of what this is trying to show.

load all of your js

I am still using jQuery and the extension dataTables but for this lesson I am using an additional plugin:
inPlace.
So now our script loading looks like this (notice I moved the script refs into the masterpage in this lesson):

decide what you want to be editable

Now, since we are using our Repeater table from the last example, we just modify if ever-so-slightly to make it editable, to do that, we just add the class 'editable' (or whatever you want it to be) to each td that we want to be editable.
In addition to adding a class, we are going to add meaningful ids to each of the cells, each ID will contain:

First 4 Letters - What field is being edited

Following digits - 'person_id' that is being edited

if you are unsure as to why we are doing this, keep reading, it will become clear.

You can look on the documentation for jquery.inplace.js for a further explanation, but what we declared there is that all items that have class 'editable' will now be editable;
also, requests will get sent to 'ajax_functions/update.aspx' (which we haven't made yet) and we are requiring a value.

handling the ajax

Ok, so what is happening now, is if you click on a cell you will be able to edit it, and when you click off, or hit enter (you can edit these behaviors if you want), a POST will be sent to 'ajax_functions/update.aspx'.
What is sent to the page is the following values:

update_value - the value you edited

element_id - the element id that was edited

original_html - value from before your edit

Now we only care about the first two in this example, but the third value could also be useful given the situation; possibly returning the old value if an error occurs?
Also, it may be easier to see why we included both the field and the person_id in the ID of the <td>.

For handling, you could easily have seperate pages that only handle a certain element, i.e. ajax_functions/first_name.aspx for first_name, ajax_functions/last_name.aspx for last_name, etc. but I found that if you did it that way, you ended up writing the same code over and over - so what I did was combine it into a single update handling page.
That is why I include 'what' is being updated in the id.

When you make your handling page, it is important that there is no html in it to start with - as the page text itself will be what is stuffed back into the area that you edited.
This is the ENTIRE ajax_functions/update.aspx page:

First off, the code simply sets the DataContext and opens a SqlConnection (it is explained why in the code).
Then, we pull from the POST values from the Request.
We pull 3 things from this:

person_id - 'person_id' that is being edited

what - what field is being edited

newValue - the new value for the update

Now is the easy part, get the 'person' to edit, run a switch on 'what' and and update it to 'newValue'.
I caught all errors and output them to Response.Write() as that is all the user will be able to see.
Also, whatever is written is returned so it integrated seamlessly. What
the user will see is 'Saving...' (unless you change the text or substitute an
image) and when it is complete, they will see the new value in place of the old
value (which is now written to the DB) as that is what was put in the Response.Write()
(if there are no errors, otherwise they'll see the error message).

There you have it! A 'real' ajax inline update with asp.net, and it was as painless as can be!
There are all sorts of other things you can do like apply a js function after the update has completed, add in a nice loading graphic instead of the text, etc. - fun to play around with.

Keep in mind with this, if a user (hacker) realizes how it works, they would be able to fabricate a POST to send to your page and update it how they see fit;
so be sure you test, protect against that.
In one of my apps that uses this. I make sure that the record being edited belongs to the user currently logged in before they can update.

but...

If I have 3 'people', with last names, 'a', 'b', and 'c', and edit 'b' to now be 'z', it will not sort correctly; 'z' will not be the last one in the table, it will still be 'c'.
That is because the table data that does the sorting is not held within the table itself, but in an array of 'nodes'.

I left that as a seperate download because this part dives a little deeper into the relation of the sort/edit.
What needs to be done is we have to go into the array that holds the nodes, and change the related data along with the represented data in the table.

how do I do that?

This one might require reading a few times, so bear with me.
First you need to set the global variables we will be using:

var oTable;
var aPos;
var editedCell;

Then, you will need to store your table in memory:

oTable = $("#sort_table").dataTable();

Now you need to intercept the click in any editable field, and get the position of it in memory; also, we will store the edited cell into a variable as well:

What is now in aPos is a 2-element array [int row_index, int cell_index]; editedCell is the cell that you just clicked.
At this point we have all the necessary values to plug the data back in.
So next we tack the '.editable()' on to the end of the previous 'click()' call and add a 'success' parameter that will fire on success of the edit.
Here is the completed js:

Also included in the setup.sql file is some dummy data to populate it initially. We ill be using a Linq as our datasource throughout with a .dbml file named demo.dbml.

Next we need to display the data. Normally if I wanted to do paging, I would use a GridView, due to the fact is is already integrated. But that integration is sloooow, and requires a postback - we are ajax'ing here! What we are going to do will load all the data (which could be slower initially on large data sets) and use jQuery to take care of all of the lifting for us. So, it is much more efficient for us to use a Repeater. Without postbacks, all the advantages of a GridView quickly fade away. You will see how little markup you need:

That is all the markup it takes, no code-behind. Now just call the javascript magic of the combination of jQuery and the extension dataTables:

sort_page.aspx

$(function() {
$("#sort_table").dataTable();
});

And just like that you have a full sortable (with flipping sorting images), filterable, sizable, pageable and 'pretty' table using a simple Repeater.
Now, I guess this isn't truly ajax, as nothing is truly pulled from the data store after the initial pull, but I argue that it is *relatively* because if you were to use a GridView jumping pages would cost a postback each time.

This is just the introduction here, but it is to show you how incredibly easy it is to get real, time-saving ajax and it is not as intmidating as you think.
Next I will be showing you how to do inline editing of this table.

Simple code coloring with this javascript library

From here on out you will notice that the code on my site will be formatted differently, and you won't know this, but it will be much easier for me to publish code. This is because I have implemented the google-code-prettify library which is freely available... and it is great! Getting it to work with BlogEngine is not too much of a hassle either; this is how I did it (there are unlimited ways to implement this, where to dave the files, etc.; this is just how I chose to).

place the files in a central location

I put mine in the root/js/ folder, just in case multiple themes were going to access it.

reference them from your site.master

I ended up putting this in the code-behind of my site.master as a precaution of where this file might (if ever) move in the future when I completely forgot how I did this. The nice thing about this is that it doesn't matter the relation to the JS, as it will always be found as long as the JS itself does not move.

If you noticed, I did not load all the language JS files included in the download, that is because I don't plan on using them, but feel free if you are a lisp, vb, etc. developer.

reference your css

Now this I am referencing simply from the site.master itself. I placed the prettify.css file in the theme/naspinski/ directory of my site.

site.master

<link rel="Stylesheet" type="text/css" href="prettify.css" />

The reason I am not doing this in any sort of global way is the fact that different themes will likely want different prettify.css files. I will have to make sure there is a prettify.css file for each theme.

**IMPORTANT**
Now, I noticed that the BlogEngine RTE liked to strip out line-breaks inside the <pre> tags so you will have to add the <br />s in there to break lines which you would normally not have to do, as well as any starting spaces with &nbsp;s. I noticed if I turned off JS while entering my post, that I did not have to do this; so I actually prefer to *not* use the rich text editor so I don't have to add the <br />s.

Now, if you look back up you see I specifically pulled a couple language scripts for use with SQL and CSS. The script as is will try to 'guess' the language you are using, but if you want to specify it you simply add it in the class declaration:

Now that it's all up and working, we can make it friendlier and add some cool AJAX effects

After part 2 the system works just fine, but I wanted to take it a step further.This will be the last entry in this series, which I will follow up with a tutorial on how to retrieve passwords and log the registered users in.

what are we going to accomplish?

Like I said before, the system works, this is just the frosting on the cake, we are going to add some jquery and use the MasterPage to make this more accessible to the users.

markup

On the MasterPage, I added quite a few things, and on the registration page I added one key element:

First of all, you have to realize, since the <div id="register" ... > has a CSS class of 'jqmWindow, it will not be visible when the page loads. This is because it is going to be within a modal popup window. Also, you will notice that there is a <cc:register ... > control within. That is what causes the small change to register.aspx as the attribute 'in_page' is added.What this does is elimiate errors that may occur if two or more of these controls are on a single page, so the validators only validate the controls they are pertinant to. The code is in the Utils.cs file if you would like to examine it.

I am also using an UpdatePanel within the modal so the user is able to see their feedback; if it wasn't (or something similar) used, the modal would be hidden after postback.

Also, some links with the class 'triggerRegister' are added, these will be the links that will trigger the modal popup (using jqModal) with the following JS:

And just that simply we made the registration available multiple ways across the entire project! If the user has javascript turned off, it will will still work just fine as we have a 'backup' register.aspx page that will handle the request.Ahh the beauty of jQuery.

Verifiying your users' email and activating thier accounts

In part 1 of this tutorial, we ended by emailing the user a verification link. In this part, we will us that to verify the user and activate their account.

markup

The markup is very basic, as almost all of your stuff will be done in the backend:

confirm.aspx

<h2>Confirmation</h2> <asp:Panel ID="Report" runat="server" />

Handle your input

This is where all the heavy lifting is done.Your user has a link which passes the verification guid in the querysting, so our verification page must parse the querystring.There are a few things we will be doing here:

Make sure there is a querystring

Make sure the Guid is in Guid format

Confirm the user from the DB based on Guid

Which is all reletively simple:

confirm.aspx.cs

if (string.IsNullOrEmpty(Request.QueryString["guid"]))throw newException("invalid inputs", new Exception("please navigate here from the provided link"));

Ok, now what was done there? First, we simply test to see if a proper querystrirng was passed, if not, it throws an error which is handled with my.Error() extension.Then it goes on to make a SqlConnection, which might seems strange as it is not necessary, *but* since we are possibly making two calls to the DB: getting the user and confirming the user (if necessary) - opening the connection will make sure it only opens once as opposed to twice if we weren't to open it; it is unnecessary, but it is ever-so-slightly more efficient.After that it goes to get the user object from the DB by the GUID, if it is found, it is then confirmed.If there are eny errors or it is not found, it is handled.

Now, since nothing is emailed or anything like that, we can assume (maybe not totally safely) that the user who confirms is the one who got the email. I suppose there could be a brute force GUID bombing of the site, but that would be incredibly inefficient, not to mention pointless as it would only activate accounts and not provide the hacker with anything.

And that is it. You now have a fully working registration system that requires email confirmation and it wasn't even that tough. Here is the code:

This registration has a slick interface and user verification

NOTE* I do not cover encryption in this tutorial, but I highly discourage storing plain-text passwords in your DB!

It is inevitable that every programmer will want to eventually make a site which requires registration.
Then you need to deal with spam accounts and all that good stuff.
This is part one of a series of tutorials, where I will show you how to set up a registration process that requires a valid email address.
I will be building on the code provided here for the next tutorial and so on.
In the future, I will also include a login process I developed that will lock out accounts after a certain amount of attempts, retrieve passwords, and all sorts of other goodies.
But before users can log in, they have to register.

I will be using a lot of other people's stuff in this example, such as jQuery, jQuery extensions, Grid960 and so on as well as a lot of my own Extensions, etc.
With that said, this is going to have a lot of 'extras' included such as Ajax functionality and some UI niceties to make it a quality interface - you can feel free to cut these parts out, but I feel it will be nice for those that want it.
All of the code referenced is included.

Storage

The first step is setting up your user table in the database.
The most important thing to think of here is: what am I going to need to collect?
I am all about being as simple as possible, so I am going to require two things: email and password - that is it.
This is what I came up with:

userid - the primary key integer

email - the user's email

password - user's password

guid - guid for verification

created - date created; both for record keeping and to see if it was not confirmed after a long time it can be removed

confirmed - whether or not it is confirmed

last try* - the last login

number of failed logins* - number of failures for lockout

The two starred items will not really be used in this too tutorial and are optional if you do not want to prevent unlimited login attempts; though they will be relevant in upcoming tutorials.

Markup

Now that we have our table, go ahead and drag it into a dbml - for this example, I will use one named db.dbml.
Now we have our access layer built, we can work on making a registration control; I will be making an ascx registration control, so it can be plugged in aywhere I want to use it.
Since I am only collecting two bits of information, this will be a simple control. Here is the markup, I will explain it afterwards:

First of all, you will notice that it is within a Asp.Net UpdatePanel which I have been trying to get away from for most things,
but for such small controls I have found that is is the best way to go about it: easy and fast.

Next you will see that I have added a Panel with an ID of "Report" - I use this as a standard in most applications as to where to output my 'updates' to the user.
This is explained here.
The code for this is included in the Extensions.cs file.

Finally you will notice that the password entry has a watermark which is called via jQuery in the MasterPage

You might notice that I am not using a password field or asking for password verification. This is something you might want to do, but for this example, security is not really a concern, simplicity is; so I figure if you can see your password, you wont screw it up. Also, since we will be adding a password retrieval function, this won't be a big deal.

Backend

That is the markup, but now we have to go to the code so it actually does something.
Now what does this have to accomplish?

Check if the Email has already been registered

Create a new entry in the users table

Send an email with a verification link

Not too much going on here, here is the code for accomplishing that, followed by an explanation:

The first thing that happens here is the check for if the Attribute "in_page" is set.
This is a bit of a sidebar as it just takes care of duplicate validators if there is more than one of these controls on the page, since I plan on showing how to use them both as a modal popup as well as a standalone page I had to add this check;
that way, if you are filling out the popup instead of the form on the page it makes sure that it will not fire the validation for the form you are not using, all it does is change the validation group.
The code is visible in the Utils class if you are curious about it.
Don't really worry about this too much right now, as it will be covered in an upcoming tutorial.

Next it checks if the email is a duplicate.
This calls the Users.cs class, we will get to that next; just remember for now it returns true if it is already in the system, false if not.

If it is new, a new user is then made and inserted into the DB via Linq-to-SQL.

An email is made and sent to the user with the link to the authorization page (which will be coevered in the next tutorial).
This is sent using a simplified Email class.
The authorization is the guid which was produced - I will cover the authorization page in the next part of the tutorial.

As you can see, this is just two basic LINQ queries, the first one retrieving a user object based on an email string.
And the duplicate check which tries to find a user with the given email, if it can, it will return true, meaning it is already in there, otherwise it spits out a false.

And that is all there is to it so far.
It is not yet a working system as the user has not verified their identity, but we have accomplished the base of a registration system:

Collected the user's email address

Collected their password

Produced a unique Guid for verification

Sent them an email to verify their identity

Now we have it all built, we just need to display everything and call the necessary scripts.
I am going to stick all of these pages within a masterpage which calls the scripts in the Page_Load:

Notice that I am calling the watermark in the masterpage.
This may seem strange, but this stops me from writing redundant code as this will take care of *all* watermarks that I will put into this project due to the versatiliy of jQuery.

All we have to do to complete this registration process is to verify the email which will be the next part to this tutorial.
I am also going to show how to add this into a registration popup.
The hard part is all finished.