SitePoint Sponsor

User Tag List

Page 1 of 3 123 LastLast
Results 1 to 25 of 69
  1. #1
    _ silver trophy ses5909's Avatar
    Join Date
    Jul 2003
    Location
    NoVa
    Posts
    5,466
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)

    ASP.NET Best Practices

    wwb's statement "Friends don't let friends use datasets" made me wish we had a ".NET Best Practices" sticky in this forum. Perhaps if we get enough responses and ideas, they will make it one.

    So, what are some lessons you've learned or "best practices" that you would recommend to people new to .NET or some of us that have been out of the .NET loop for a bit?

    A big one for me I think that people coming from other languages do is use String concatenation rather than using the StringBuilder.

    1. StringBuilder will be much better for performance over string concatenation.
    Sara

  2. #2
    SitePoint Author silver trophybronze trophy
    wwb_99's Avatar
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    10,629
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Great idea!

    Though I would already put some caveats in number 1 there. Mainly that using a StringBuilder makes sense if there is an unknown number of additions, where given a known number of additions using normal concatenation is no less expensive then using a stringbuilder.

    Ex:

    Good use of string builder:
    Code:
    System.Text.StringBuilder sb=new StringBuilder();
    string[] stufftoadd=MyObject.GetStuffToAdd();
    for (int i=0; i<stufftoadd.Length; i++)
    {
        sb.Append(stufftoadd[i]);
    }
    Bad use of a stringbuilder:
    Code:
    System.Text.StringBuilder sb=new StringBuilder();
    sb.Append(string1);
    sb.Append(string2);
    sb.Append(string3);
    Now for my first few:

    2. Thou shalt not use exceptions to manage program flow. Throwing an exception is a very expensive operation--basically the most expensive thing short of calling external resources. Think of an exception as making the computer beep twice and pause for two seconds, then think if you actually want to use one in that place.

    3. Thou shalt wrap calls to external resources, such as configuration values or session variables in strongly typed properties.

    4. Thou shalt not use DataSets in web applications.

    Thats all for now, stay tuned for more.

  3. #3
    SitePoint Wizard big_al's Avatar
    Join Date
    May 2000
    Location
    Victoria, Australia
    Posts
    1,661
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    5. Thou shalt wrap any disposable items in a using statement
    i.e. using(SqlConnection cnn = new SqlConnection())


    6. Thou shalt employ and ALWAYS adhere to naming conventions!

    7. Thou shalt not deploy a live site when compiled in 'Debug' mode.

    8. If you HAVE to throw an exception, thou shalt use throw, not throw ex; or thy stack trace will be reset.

    9. Thou shalt disable viewstate on any control that does not need it.

    10. Thou shalt always check a variable for null.

    11. Thou shalt use HtmlTextWriter when outputing html from code, not Response.Write.

    12. Thou shalt use Server.Transfer, not Response.Redirect when moving to another url programatically.

    13. Thou shalt only use user controls when it is required on more than one page.

    14. Thou shalt turn off session state support if session state is not required.

    15. Thou shalt use caching.

    16. Thou shalt not hard code paths in code.
    i.e. string appPath = "c:\test\blah.txt";

    17. thou shalt never catch general exception, though shalt use the appopriate exception type
    i.e.
    try
    {
    SqlConnection cnn = new SqlConnection(BadCnnString);
    cnn.Open();
    }
    catch(SqlException ex)
    {
    // now handle it gracefully
    }

    I got plenty more, but better get back to work, will post more later
    .NET Code Monkey

  4. #4
    _ silver trophy ses5909's Avatar
    Join Date
    Jul 2003
    Location
    NoVa
    Posts
    5,466
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    following suit here:

    18. Thou shalt store any application data (connection strings, etc.) in the configuration/appsettings section of the webconfig and reference it accordingly: System.Configuration.ConfigurationSettings.AppSettings["myKey"]

    19. Thou shalt not create a variable if it is only used once.
    Sara

  5. #5
    SitePoint Guru pufa's Avatar
    Join Date
    Oct 2004
    Location
    Portugal, Lisboa
    Posts
    947
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    A basic one...

    20. Thou shalt not concatenate SQL queries and user input... use Parameters.

    About DataSets and Custom Entity Classes
    On the Way to Mastering ASP.NET: Introducing Custom Entity Classes

    http://msdn.microsoft.com/library/de...CustEntCls.asp
    Ciao, Rui...

  6. #6
    SitePoint Guru pufa's Avatar
    Join Date
    Oct 2004
    Location
    Portugal, Lisboa
    Posts
    947
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    By the way...

    What do guys (and lady) have to say about the new "...DataSource" controls?


    I went to TechDays last week here in Lisbon... the ASP.NET presentations where the "drag-and-drop" madness!!

    Cheers,
    Rui
    Ciao, Rui...

  7. #7
    SitePoint Guru puco's Avatar
    Join Date
    Feb 2005
    Location
    Slovakia
    Posts
    785
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    21. Thou shalt catch all exceptions before they are thrown to the end-user. After all there is a nice HttpApplication.Error event that is just for that purpose. And give user a nice error page, not the ASP.NET generic one

    Quote Originally Posted by big_al
    5. Thou shalt wrap any disposable items in a using statement
    i.e. using(SqlConnection cnn = new SqlConnection())
    Or dispose them in finally section of you exception hadling statement. (Especialy for the VB.NET people) And instantiate them as late as possible and dispose them as early when you don't need them anymore. (mainly for DB connections, images, streams)

    Quote Originally Posted by big_al
    7. Thou shalt not deploy a live site when compiled in 'Debug' mode.
    Also don't forget to turn off in web.config:
    Code:
        <compilation debug="false" />
    Off Topic:

    Thou shalt not overgeneralize: "12. Thou shalt use Server.Transfer, not Response.Redirect when moving to another url programatically." is IMHO not good, they can be both used and have their distincitve usages.
    Martin Pernecky

  8. #8
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Now, I'm always a little provoked when faced with absolutes. wwb has several times floated the idea that datasets are generally unwanted in web applications. I assume it's because of performance concerns.

    There are situations where a dataset may actually both improve your program structure *and* improve performance, unless you go to extreme length with your plain C# objects.

    One such example is when you have a hierachical entity which is stored flattened in the database. This could be an agenda of a meeting planning system with several thousands or more agendas. You wouldn't want to go to the database to find the "root" item and after that find the next level (sub items of the root item) and go on like that recursively. That would generate a database chatty application. Chatty apps is *the* most common source of scalability/performance problems, especially when the database server is accesses across a network. Rather you would like to get all the items of the agenda at once (since you know you'll be using them all), and arrange them in the structure within the app. The dataset is ideal for this: You can define relations, switch of index generation while loading, and then simply walk the sub-item relation, using views with orderings. In my experience this scales a lot better than the chatty alternative. Now you *could* read all the items into business objects, locate the root and try a custom indexing/searching/sorting, but you would have a hard time keeping up with the optimized dataset.

    Another - related - example is when you need to display a hierachy of records from multiple tables. In SQL server 2000 you could have only 1 reader open per connection. Walking a hierachy with only one reader can be a bit of a challenge without in effect making several roundtrips to the database. Also you might be tempted to get around the single reader problem by using multiple connections, one per concurrently open reader. With 3 tables participating this will effectly cut your connection pool to 3rd the size, having profound impact on the scalability of the app. Again the dataset can be used to load the relevant records into several tables using a command batch (single roundtrip - no chatting). Utilizing crafted relation walking the hierachy is almost a walk in the park.

    In general - if used prudently - the dataset has the capacity to actually improve the performance of a program in the scenarios where you must scramble several tables - or even datasources - and make some structure of them before displaying.

    Also the dataset can be great for capturing the business activity (business transaction) before the actual update is to take place.

    In short I find the outlawing of the DataSet a little unbalanced. It's not all black and white.
    /mouse

  9. #9
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Now, my post about the DataSet was not meant to encourage its use in web apps. Most web pages have much simpler display requirements, and will work just fine (and faster) using data readers.

    Also, if you are using an extensive system of business objects and have coded (or code-generated) custom collections to support eventual queries, the dataset has no place. DataSets essentially promotes the 2-tier approach (I'd call it 2 tier) where the app "knows" about the database structure. This is perfectly valid for smaller apps, but for more complex apps you should always build business objects. ORM mappers are great ways to have both query capability, database abstraction and automatic caching.
    /mouse

  10. #10
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    22. Thou shalt initialize default values of page and control members as attribute values or in Page_Init, not in Page_Load.
    Initializing variables in page_load will add viewstate pressure, as viewstate tracking has begun at the load time.

    23. Thou shalt disable viewstate for controls that does not explicitly need to maintain viewstate.

    This is especially true for display-only pages with no interactivity.
    /mouse

  11. #11
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    24. Thou shalt set EnableSessionState of the @Page directive to false if your page does not require access to session state.
    Doing so will allow the app server to not spend cpu cycles on deserializing/serializing the session state before and after execution of the page handler.

    25. Thou shalt set EnableSessionState of the @Page directive to ReadOnly if your page does require read access to Session state but does not change any values.
    Doing so will allow the app server to schedule more requests in parallel and free it from serializing session state after page rendition.
    Last edited by Benjymouse; Dec 13, 2005 at 16:26.
    /mouse

  12. #12
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    26. Thou shalt minimize the number of roundtrips to the database server
    For the ultimate of scalability and low latency you should only read from the database when nessecary (e.g. not reading from the db if all controls' state can be safely restored from viewstate). When you *do* access the database, you should consider reading more data at once, saving later database access. This could preferably be done in a command batch (supported by SQL server).
    /mouse

  13. #13
    SitePoint Guru
    Join Date
    Dec 2003
    Location
    oz
    Posts
    819
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Benjymouse
    Now, I'm always a little provoked when faced with absolutes. wwb has several times floated the idea that datasets are generally unwanted in web applications. I assume it's because of performance concerns.

    There are situations where a dataset may actually both improve your program structure *and* improve performance, unless you go to extreme length with your plain C# objects.

    One such example is when you have a hierachical entity which is stored flattened in the database. This could be an agenda of a meeting planning system with several thousands or more agendas. You wouldn't want to go to the database to find the "root" item and after that find the next level (sub items of the root item) and go on like that recursively. That would generate a database chatty application. Chatty apps is *the* most common source of scalability/performance problems, especially when the database server is accesses across a network. Rather you would like to get all the items of the agenda at once (since you know you'll be using them all), and arrange them in the structure within the app. The dataset is ideal for this: You can define relations, switch of index generation while loading, and then simply walk the sub-item relation, using views with orderings. In my experience this scales a lot better than the chatty alternative. Now you *could* read all the items into business objects, locate the root and try a custom indexing/searching/sorting, but you would have a hard time keeping up with the optimized dataset.
    Yes, that would be a problem, and beginners to object modelling (and object loading) would cause major problems with this. But begginners in anything cause problems. It's not an object vs relational/dataset issue . It's a lack of experience issue. It's also not going to extreme lengths. It may seem challenging if you haven't done it before, but it's very basic.

    If you have a customer and they have a number of subscriptions and each subscription is to a service and those subscriptions need to be send out on certain days of the week (this example is from actual system).

    The customer db object has a method Load that is called with the db resultset as a parameter and goes through each row and loads the data for the customer, or calls load on the Subscription object and adds that to the SubscriptionList object via the subscription db load method. It also calls the Load method of the SendDays which loads its own data. This gives you an object model instead of a relational model which is easy to manipulate and easier to imagine when thinking about the problems, as it's a logical object model instead of a relational one. And is loaded with a single database call.

    Quote Originally Posted by Benjymouse
    Another - related - example is when you need to display a hierachy of records from multiple tables. In SQL server 2000 you could have only 1 reader open per connection. Walking a hierachy with only one reader can be a bit of a challenge without in effect making several roundtrips to the database. Also you might be tempted to get around the single reader problem by using multiple connections, one per concurrently open reader. With 3 tables participating this will effectly cut your connection pool to 3rd the size, having profound impact on the scalability of the app. Again the dataset can be used to load the relevant records into several tables using a command batch (single roundtrip - no chatting). Utilizing crafted relation walking the hierachy is almost a walk in the park.
    I've never needed to open a second connection for a query while another query was running (unless to another database). But more generally, I think this goes back to the first issue, which really was the concept that going to a database shouldn't be done for each part of a problem, it should return all the data needed for the use case scenario in one call - in the same way that any Service Oriented Architecture should avoid chatty calls over a network.

    Quote Originally Posted by Benjymouse
    In short I find the outlawing of the DataSet a little unbalanced. It's not all black and white.
    Yeah, its there because it makes life easier. It's not logical to ignore something like that.

    My main problem is that it returns relational data rather than in a logical object model. This makes you think in terms of data rather than in terms of behaviour. A system does stuff. It doesn't just hold data. And using data as you do in DataSets means it is harder to understand the conceptual entities in the system because the entities are data tables, not objects with behaviour.

    I use data readers if processing large records for batch processin because the cost of creating millions of object is too much of a performance hit. You also can't use datasets for the same reason. For smaller things, I use objects for the above reasons.

    I really find that datasets are only useful for very small apps where you don't need to have a conceptual model of the system becuase it's so simple, and where performance is not something you need to think about because a dataset keeps all the data in memory.


    Quote Originally Posted by Benjymouse
    Also, if you are using an extensive system of business objects and have coded (or code-generated) custom collections to support eventual queries, the dataset has no place. DataSets essentially promotes the 2-tier approach (I'd call it 2 tier) where the app "knows" about the database structure. This is perfectly valid for smaller apps, but for more complex apps you should always build business objects. ORM mappers are great ways to have both query capability, database abstraction and automatic caching.
    Absolutely. Datasets are ideal for simple apps that you want finish and ship super fast.

    Btw, excellent point on chatty interfaces. People often talk about chatty interfaces in larger scale architectures, but miss the point that accessing anything on another machien (including the database) is exactly the same.

    Regards,
    Eli

  14. #14
    SitePoint Author silver trophybronze trophy
    wwb_99's Avatar
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    10,629
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by Benjymouse
    good stuff about datasets
    Very valid points. My main reasons for discouraging the use of datasets is that they tend to be overkill for most situations one sees on the web. Your two examples are very good cases where a Dataset would be a reasonable compromise. You also touch on another reason--using a dataset almost by definition encourages the data tier to bleed over into the presentation layer. Finally, beginners tend to overuse them because they are so fast and easy with the drag-n-drop tools. If you have ever inherited one of these apps to fix or integrate, you know what kind of nightmares you are talking about.

    So, just like every one of the commandments, there are a number of exceptions to the rules. One should just understand all of Leviticus and Deutoronomy before one starts using the exception.

    As for massive data processing, one should be able to generate large SQL updated/insert/delete statements to handle sweeping changes to sets. If one is calculating values on a per-row basis and requiring a cursor, one really should rethink how they are using that bit of SQL.

    And I don't ignore the dataset. I abuse the living daylights out of datasets as temporary storage for non-web projects where one tends to be dealing with less data and definitely far fewer concurrent users. In fact, in the non-web world, the disconnected data model of the data set is a very handy thing.

    12. Thou shalt use Server.Transfer, not Response.Redirect when moving to another url programatically.
    Any particular reason for this? In terms of user experience, redirect is more friendly. I think it really is a situational thing.

    13. Thou shalt only use user controls when it is required on more than one page.
    Again, any particular reason for this. I find user controls to make sense from an architectual perspective. Also note that I have a slightly different view than most here because I mainly work on apps for my current employer which I will have to live with for years rather than a love-em-and-leave-em consulting gigs.

    21. Thou shalt catch all exceptions before they are thrown to the end-user. After all there is a nice HttpApplication.Error event that is just for that purpose. And give user a nice error page, not the ASP.NET generic one.
    Very good point, though a bit difficult to follow. Depending on how you read it, it could be constructed to say "catch all errors and hide them" which is about the worst thing one can do. If your data-driven web app starts having database connection issues, you really should error out before corruption occours. In any case I think what you are really mean is:

    21. Thou shalt bubble exceptions where appropriate to a global error handler which shall wrap the exception in a pretty way for the user and log/notify the administrators.
    I would also extend #26:

    26. Thou shalt minimize the number of roundtrips to external resources.
    Database server can just as easily be a webservice call (which can take 10x as long).

    And I will add one (which summarizes alot of recent points):

    27. Thou shalt use common sense.

  15. #15
    SitePoint Wizard big_al's Avatar
    Join Date
    May 2000
    Location
    Victoria, Australia
    Posts
    1,661
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wwb_99

    Any particular reason for this? In terms of user experience, redirect is more friendly. I think it really is a situational thing.
    Server.Transfer saves a round trip to the browser, the only real down side to that is that the browser is not aware of page change.
    .NET Code Monkey

  16. #16
    SitePoint Author silver trophybronze trophy
    wwb_99's Avatar
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    10,629
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Good point in some cases, though I think it is really a situational thing.

    (PS: this is a poor excuse for a post-thanksgiving bump for a very good thread).

  17. #17
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I must admit that I have completely left Transfer out of my arsenal, except for very, very special cases.

    I know the redirect generates an extra roundtrip, but it merely incurs the overhead of the http request itself. The serverside code that must be executed will be the same. This extra overhead IMHO is outweighted by the potential problems with Transfer. Among the issues are:

    - It confuses the address line of the browser. Bookmarking a page to which the server transferred will bookmark the previous page url, creating usability problems, confusion.

    - It tends to make the browser "back" and "refresh" buttons behave in an unintuitive way, e.g. if I use the Transfer back to a "list" page after a details edit page, the refresh button will try to resubmit the last edit.

    - It can interfere with standard browser statistics programs like webhound. The actual url read from logfiles will not correspond to the pages actually shown.

    - You can not trust the securing of a single page (by placing it in a restricted folder). Pages that transfer to another page will bypass the folder restriction. While this can certaintly be used to fine-tune security it can most certaintly also result in poor overview of your security structure.
    /mouse

  18. #18
    SitePoint Author silver trophybronze trophy
    wwb_99's Avatar
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    10,629
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    This thread really needs a sticky . . .

    A few recent things that should be added:

    28) Thou shalt not use Server Side Includes (<!-- #INCLUDE -->). Thou shalt use user controls or master pages.

    29) Thou shalt not use Response.Write. This includes the shorthand <%= somestuff %>.

  19. #19
    _ silver trophy ses5909's Avatar
    Join Date
    Jul 2003
    Location
    NoVa
    Posts
    5,466
    Mentioned
    1 Post(s)
    Tagged
    1 Thread(s)
    Quote Originally Posted by wwb_99
    This thread really needs a sticky . . .
    I'll get on that.
    Sara

  20. #20
    Wanna-be Apple nut silver trophy M. Johansson's Avatar
    Join Date
    Sep 2000
    Location
    Halmstad, Sweden
    Posts
    7,400
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by ses5909
    I'll get on that.
    Made it featured as well. Man, this is a good thread.
    Mattias Johansson
    Short, Swedish, Web Developer

    Buttons and Dog Tags with your custom design:
    FatStatement.com

  21. #21
    SitePoint Guru puco's Avatar
    Join Date
    Feb 2005
    Location
    Slovakia
    Posts
    785
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wwb_99
    29) Thou shalt not use Response.Write. This includes the shorthand <%= somestuff %>.
    Are you sure on this one? I mean, yea, you shouldn't overuse it, but I think it is has its place in ASP.NET development. For all the resources etc it's priceless. Plus it really does what you would expect it to do. It renders some text in the Render stage of the Page life cycle, which is IMO good. You wouldn't suggest to insert a server control in each place a string has to go and fill them on load or by god serialize them into the viewstate of the page.

    It should be added that MS included a brand new feature to include resources into pages: <%$ Resources: MyResources, MyText %>.
    Martin Pernecky

  22. #22
    SitePoint Author silver trophybronze trophy
    wwb_99's Avatar
    Join Date
    May 2003
    Location
    Washington, DC
    Posts
    10,629
    Mentioned
    4 Post(s)
    Tagged
    0 Thread(s)
    Valid points about the declarative binding, but I use databinding (<%# something %>) instead.

    Funny enough, I started looking around for backup to the "don't use Response.Write()" and have found nothing official or semi-official indicating it is a bad idea. One wonders if it is actually an urban legend.

  23. #23
    SitePoint Wizard
    Join Date
    Jan 2005
    Location
    Denmark
    Posts
    1,222
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wwb_99
    Funny enough, I started looking around for backup to the "don't use Response.Write()" and have found nothing official or semi-official indicating it is a bad idea. One wonders if it is actually an urban legend.
    You may get away with it directly in the markup like:
    <% Response.Write("Booh!"); %>. It will even work inside some templates, but it will not work with databinding.

    Inside the codebehind/codebeside it's uncontrollable. For example, executed in Page_Init or Page_Load, Response.Write will write text in front of the document declaration.

    Nikhil Kothari and Vandana Datye says: "[...] Do not directly invoke Page.Response.Write from your controls because doing so breaks the encapsulation provided by the page framework".

    Generally it's ill aligned with the page lifecycle. Its not an urban legend.

    Databinding expressions though, are perfectly fine.
    /mouse

  24. #24
    SitePoint Wizard big_al's Avatar
    Join Date
    May 2000
    Location
    Victoria, Australia
    Posts
    1,661
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by wwb_99
    Funny enough, I started looking around for backup to the "don't use Response.Write()" and have found nothing official or semi-official indicating it is a bad idea. One wonders if it is actually an urban legend.
    I remember seeing an interesting article on a blog titled somthing like "Real Programmers don't use Response.Write", I'll see if I can find it

    Why would someone use Response.Write to output html when you can use the HtmlTextWriter, much nicer IMO.

    As for the Server.Transfer, you WILL notice a HUGE difference in server performance if you have a highly utilized website, as Response.Redirect creates a new request which the server will handle.

    Also, add a good ol' true in to your Server.Transfer and your form and querystring collections are retained, no more reading query strings and "re-attaching" them

    Also, in the majority of cases you will be using the transfer mechanism for things like redirecting from a login page to an error page or new home page, and IMO those do not need to be bookmarked at any time

    If one where to use a lot a redirects in an applications I think it's time to re-evaluate their design because it sure as hell won;t be scalable

    30. Do not cache a database connection in Application or Session objects
    .NET Code Monkey

  25. #25
    SitePoint Wizard Dangermouse's Avatar
    Join Date
    Oct 2003
    Posts
    1,024
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Can we get explanations with the rules


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •