Pages

Monday, June 7, 2010

ASP.NET and SQL Server: Chapter 1: Displaying A Gridview of SQL Server Data

Chapter 1.
Assuming you already have data you wish to display in your SQL Server database, create an aspx ajax web form.

Now open the Database Explorer, and open your database, then navigate to the table you want to show in the web form.  Click the table, and drag it to your form div tags.
Hit control-s (save) and your datagrid will appear in the design view window along with a SqlDatasource.

That was easy!  As a bonus, there are some handy easy-formatting options.  Click the grid in the design view, and look for the little pop-out menu at the top right of the control.  Select AutoFormat.
The Auto Format options can configure all the visual settings for you in a flash.  This menu is also used to select editing, paging, sorting options for the gridview.

Press F5 to view the grid in action.  Then stay tuned for Chapter 2: How to use a dropdown list in the grid.

Friday, June 4, 2010

How to Design a Crappy Web Site

Ok, no one really needs information on how to make the worst possible web site.  This article was written as a guide how not to do a web page for your business.  As a professional web designer I am well-versed in all the nerdy ways required to carve a web site out of solid stone.  What I offer here is a humorous attempt to get you thinking about the things a business needs to consider before creating or redesigning your web page.

First, have no idea what you want to say.
After all, you hired a professional programmer... He should just know what you need to put on the web to take your sales profile from zero to hero.  Right?!?  He can just make it all searchable, sortable, buzzwords that hypnotize viewers into cranking out that credit card.

Next, have no goals in mind for your site.
When your web designer asks questions like "What are the goals for this site, to generate phone calls, foot traffic, direct Internet sales, gathering club members?", make sure that you don't have a good answer to that.  Tell him something vague like we just want sales.

Content is overrated.
Your web designer is a trained professional.  He should have access to all the photos, text, articles, and everything that he needs to make your site.  It's far too much work to make a list of pages and mock them up in Word for him.  Besides, thats how he earns his keep, right? 

Photos
Make sure any site photos you provide are a little blurry, an unreasonable size (like 30,000x22,000 pixels), in an antiquated image format (daguerreotype if possible), badly lit, and full of really ugly people against distracting backdrops.  If possible, take these near your competitors billboards and other signs.

Speak in generalities and marketing lingo about layout.
When your web designer asks what colors, themes, and logos you want to use, give him a description of feelings, couched in marketing weasel words.  He may expect things like "We'd like a 3 column layout in mauve and yellow with this banner and our company logo.  We'd like a button menu across the top, our sales ads in the center,  and an RSS feed of our blog articles in the right column.", but do NOT tell him that.  Say things like, "We are committed to challenging unquestionable management leadership with expansion through opportunities overcoming all obstacles."  You know, try to avoid the mention of colors, layout terms, and anything that can actually be used to - I don't know - figure out where to put stuff on a screen.


Web Design is an iterative process.
So every time your web designer sends you an email asking you to approve something here's what to do.
  1. Wait 4 to 12 days before responding.
  2. When you do call, ask why it's going so slow.  Say things like "I thought you said you were good at this."
  3. About the work you're reviewing, respond with more generalities like, "I was thinking of something more youthful and clean.
  4. It's more fun to wait until the second time around to show him examples of what you're looking for, but throw in a few spoilers you hate - it makes the job of looking for a common thread more fun!
  5. Wait until the fourth go-around before you mention the name of an actual color or pattern.
  6. Try to keep the process going forever.  This is all part of the initial quote, right?
Advertising
Don't set aside any money for advertising your site. A good web site will become popular even if you never tell anyone it's there.  Sales will just flow in, even if you never really gave enough information to let people know how to buy.  Don't integrate with tools to help you track your traffic and link to your sales.   Either it will work and you'll sell like crazy, or it won't, in which case it was the web designers fault.  It's a no-lose scenario!


Going forward
Once your site goes on-line, it's important to let your web designer know that your hits are not increasing, and you're not making many sales.  Even if you're up 4% with no advertising, you were expecting 20%.  Try to use this guilt to get the designer to "fix" his "broken concept" for free as a defect, rather than pay him to "redesign" the site.


In Contusion...
Seriously, think of your web designer like you would think of a printing house you use to create a catalog or magazine.  A good one is very qualified to take your ideas and present them on the World Wide Web in a way that will help you achieve your goals.  You would never expect a printing house to take photos or write copy, or even to create a corporate image for you.  You should not expect this of your web designer either.

Tuesday, June 1, 2010

No connection could be made because the target machine actively refused it

This happened after migrating from a T1 line to a Comcast 10Mb line.   My web sites can no longer send emails because of this error. 

My setup:

I am using SBS 2003 as a web server AND as an Exchange server.  The ASP.NET code that is trying send an email looks like this:

   1:      protected void Button1_Click(object sender, EventArgs e)
   2:      {
   3:          if (IsPostBack)
   4:          {
   5:              MailMessage myMessage = new MailMessage();
   6:   
   7:              myMessage.To.Add(new MailAddress("myAddress@gmail.com", "Me"));
   8:              myMessage.Subject = Regex.Replace(Subject.Text, @"<(.|\n)*?>", string.Empty);
   9:              myMessage.ReplyTo = new MailAddress(email.Text, name.Text);
  10:              myMessage.Body = Regex.Replace(messagebody.Text, @"<(.|\n)*?>", string.Empty);
  11:   
  12:              SmtpClient MailMan = new SmtpClient("209software.com");
  13:              MailMan.EnableSsl = true;
  14:              try
  15:              {
  16:                  MailMan.Send(myMessage);
  17:              }
  18:              finally
  19:              {
  20:                  ;
  21:              }
  22:              
  23:          }



Diagnosis:
In my case, we had switched from a T1 to a 10Mb line.  everything was configured the same but we *did* get a new IP address, which we changed in the server appropriately. HOWEVER. on this new line, provided by Comcast, hitting our IP address from inside the network gets redirected to Comcast Business Gateway.  Let me demonstrate.   From the outside world, my website looks like this:


However, when I remote into my server, I see this:

Somehow the Comcast Business Gateway is intercepting hits to my IP Address from inside the network.  This causes all requests from my ASP.NET applications to email stuff using my Exchange server to go not to my server, but to this Comcast monstrosity.

The Solution:
What I did was so simple - I am embarrassed to say it took me overnight to think of it.  I logged into the webserver and added all my websites to the HOSTS file (C:\windows\system32\drivers\etc\hosts) like this:

127.0.0.1 209software.com www.209software.com mail.209software.com
Now my server can access itself when it needs to.  BTW This is a very lame approach on the part of Comcast.  I officially hate it.

Friday, March 12, 2010

General SQL Optimization Tips and Tricks

SQL and You
SQL can get complicated.  You are simple.  That's just the way it is.  You like issuing commands like...

select * from orders
...when all you need is a few columns.  But the SQL Server will dutifully fetch all the data you requested, no matter the cost to the performance of the server, the network, and your fellow database users.

The above query might not be too bad, but when you see what an order looks like...

...you figure out you need to join in some additional data to make a meaningful report.
so you join to the customer table, and your query becomes:
select o.*, b.billto_firstname+' '+b.billto_lastname as CustName from orders o
join buyerdata b on b.OrderID = o.OrderID
...giving us a concatenated name...

Ok, time goes on and you add joins to categorize the orders by state, product type, salesman, etc. etc. etc. until your SQL gets into a state we like to call gnarly.  Another thing that happens is that your SQL is written to make life easier for you, not for the database server.  Soon, your query gives you the perfect data, and your report/web site/whatever looks amazing - after minutes of crunching to gather the data.

This article is written to help you find and correct some common things that make queries easy for us, but difficult for your database server.  This process in general, is called query optimization and companies pay big bucks for people who are experts at this.  Imagine a business with 800 users entering data on their desktops.  Some are on the phone with vendors or clients, and system performance is mission critical.  Suddenly you launch off the un-optimized query for your weekly TPS report, and the entire database starts chugging like The Little Engine That Could.  This means hundreds of your business clients all start hearing words like "Geez, hang on - this screen is loading...".  You can see the business need here.

Even if your business is small, why tax your systems needlessly if you can take a few steps to write better SQL that gives you the data you need faster?  I promise - if your small business grows big, that query that generates a report out of your 1MB database in 3 seconds now will probably take 30 seconds when you reach 10MB and 5 minutes at 100MB. 

Tip 1:  Never use Select *
Select * is great for when you just want to get a feel for what data is in a table.  But it's the least efficient thing you can do in a production query.  Think about it.  First, the parser has to access the data dictionary and fetch the names and types of all the columns in the table (or multiple, joined tables).  Then your '*' is replaced with all the names of the columns - which (by the way) are not guaranteed to be in any particular order under ANSI SQL specs.  If you are writing a query for production use, one that will potentially execute thousands of times a day, take the time to tell it which columns to return.

Tip 2: Indexes
Indexes are designed to help queries. If you're summarizing sales by agent, then adding a secondary index to the agent column in your sales table will save you a lot of time.  Technically the time is being spent, but it's being used in tiny slices whenever you change data in the sales table.  That triggers the maintenance of the index, which can then be searched much faster than the whole table.

Tip 3: Case Insensitive Searches
Consider:
Select fname, lname, email from Customers where lastname='McHenry'
This query might work, unless you're looking for all people who entered any of these: McHenry, mchenry, Mchenry, MCHENRY, McHENRY.  ok - so you want to just find the customers with a case insensitive search.  So you do this:
Select fname, lname, email from Customers where lowercase(lastname)=lowercase(@searchname)
What happens now? The query is executed not against the field "lastname" (and any indexes applied to it), it is instead executed against the function lowercase(), which has no index.  There are two common workable solutions to this issue.   Neither of the solutions is to make sure all data is entered using strict capitalization standards. No one wants to be the Capitalization Nazi!
  1. Use a function index.  Oracle supports these. you can actually make an index on "lowercase(field)" or "getmonth(datefield)".  This is not a widespread feature, but is really useful in these cases.








  2. Add a lower or upper column in your data to use for joining and searching.  If you have an ASP.NET membership provider database, note that the aspnet_users table has a column named LoweredUserName.  If this approach is good enough for Microsoft, it's good enough for me.
Tip 4: Data Warehousing
Sometimes you just *must* have that report that performs a 23 table join against a 40 million record database.  There's just no way you can put out your TPS reports without it.  What many companies do is perform certain data mining and harvesting tasks once per day, rolling up and summarizing certain data into a "data warehouse" for offline reporting needs.  This data is often de-normalized to make faster queries and it's usually stored on a different database server and even a different network to prevent reporting from slowing down the workday.
The idea is that you create a query that performs certain common joins and relations... rolls up hourly/daily/monthly or whatever kind of totals, creates various types of crosstabs, and stores the rolled up data in a reporting database.
These summaries are run during off hours (or infrequently during the workday) to prevent the database servers from clogging with work while you're open for business.
Managers and their lackeys can hammer away at the reporting database all day long and your main operation could not care less.

Tip 5: Joins vs. Sub-Selects
Sometimes when you just want a single lookup from a table (say decoding a County ID to a name) , it's faster to not join in the county table.  Some SQL servers can detect this kind of lookup and perform this optimization for you.  Note...

select U.UserName, RR.RoleName from aspnet_Users U
join aspnet_UsersInRoles R on R.UserId=U.UserId
join aspnet_Roles RR on RR.RoleId=R.RoleId
We have joined the aspnet_UsersInRoles table to get the ROLEID of the user's roles, and joined the aspnet_Roles table to get the name of the roles for the user.

Note the difference here:

select U.UserName,
(select RR.RoleName from aspnet_Roles RR where RR.RoleId=R.RoleId) as Role
from aspnet_Users U
join aspnet_UsersInRoles R on R.UserId=U.UserId
See how we're using the sub-select to pick up one field?  The thing about this tip is that sometimes the former way is faster and sometimes the latter.  You have to experiment.

Tip 6: Explain Plan/Query Optimizers
Ok, most SQL Servers have a module called a Query Optimizer.  This module can take your weak, human SQL and tweak it before execution to improve performance.  But there is also usually a UI that you can use to performance tune your queries.  I know Oracle has this, and have used it many times.  It breaks your query up into chunks called a query plan, and assigns an estimated cost to each part of the plan.  You can then alter the text of your query to improve the overall performance.

Tip 7:  Query Hints
On the rare occasions when your SQL is tricking the optimizer into taking the wrong approach to your query, Oracle and SQL Server have the ability for you to add query hints to your SQL.  These hints can tell the optimizer to use a specific kind of cursor, or prefer a different index, and alter the query plan used during execution.
The syntax differs greatly between the various SQL servers (Oracle/MSSQL/etc.), and will be shown only as an example here.
  1. SQL Server
  2. More SQL Server
  3. Oracle
Tip 8: Views
Sometimes creating a view can help optimize your query.  The idea is to optimize the SQL for certain common transactions and save it as a view, making the need to reinvent the wheel significantly lower.  But there is also such a thing as a materialized view. This is a type of view that is maintained like an index, as the live data is stored in the main tables.  A normal view does not store it's own data, but a materialized view does.  The view's data can then be queried without having to do whatever complex joins were needed to generate the data.  Of course the trade-off here is storage space.

Monday, February 15, 2010

The Latest Windows Malfunction

Lately my DSL has been wonky at the office.  Seemingly, everything is fine, but now and then, I get the little networking icon in this state - - sending but not receiving.

To fix this problem, I have been right clicking the little icon, opening my network connections, disabling and  enabling my network connection, and I'm good for another 15 minutes to a day.

Sometimes however, I have some process I'd rather not disconnect, so I try the good ol' XP repair connection function. Sometimes it works.  Sometimes it doesn't.  And then, sometimes, it does this:

 

Note how Windows is supposedly "finished", yet we don't have the "close" button, we have the "cancel" button.  You can click that button 30 million times and nothing is going to happen - believe me, I have tried.  That effing window is going to be there until you reboot.  There is no process in the process explorer to cancel, there is no application to end task on, you can disconnect the network and reconnect, and the little window stays right there.  God forbid you have some process running, and need it to complete first.

I wonder if the new Google Chrome will be any better.

UPDATE
This turns out to be a conflict between Zone Alarm and AVG anti-virus!  Remove one or the other and your troubles will cease!

Wednesday, December 16, 2009

Using MSSQL to Calculate Map Distances

This procedure will show you how to create a SQL Server function that accepts 2 map coordinates in and calculates the surface distance between them.

First we will create the function.



SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:  Bryan Valencia
-- Create date: 12/16/2009
-- Description: takes latitude/longitude for 2 
--   places on Earth and gives the spherical distance.
-- =============================================
DROP FUNCTION Geo_Distance
GO 

CREATE FUNCTION Geo_Distance
( 
 @lat1 float,
 @long1 float,
 @lat2 float,
 @long2 float
)
RETURNS float
AS
BEGIN
 
 DECLARE @r float 
 --radius of the Earth
 --select @r=3437.74677 --(nautical miles)
 --select @r=6378.7 --(kilometers)
 SELECT @r=3963.0 --(statute miles) 
 
 --radians
 DECLARE @radlat1 float
 DECLARE @radlong1 float
 DECLARE @radlat2 float
 DECLARE @radlong2 float
 
 SELECT @radlat1 = RADIANS(@lat1)
 SELECT @radlong1 = RADIANS(@long1)
 SELECT @radlat2 = RADIANS(@lat2)
 SELECT @radlong2 = RADIANS(@long2)
 
 --calculate answer (from http://www.sqlteam.com/article/intro-to-user-defined-functions-updated)
 -- and http://www.meridianworlddata.com/Distance-Calculation.asp
 
 DECLARE @answer float
 SELECT @answer = @r * ACOS(SIN(@radlat1)*SIN(@radlat2)+COS(@radlat1)*COS(@radlat2)*cos(@radlong2 - @radlong1))
 RETURN @answer

END

GO


So now we have a function to accept two lat/long coords and return the distance.  To use it in a select, (assuming you have a data table of geodata organized by zip code, like this... Access Zip Code Database.

Import this data to SQL Server and then use this select statement.



Select distinct Z1.[ZIP Code], Z1.City, Z1.[State Code], 
 dbo.Geo_Distance(
  cast(Z2.Latitude as float),cast(Z2.Longitude as float),
  cast(Z1.Latitude as float),cast(Z1.Longitude as float)) as Distance 
 
from [ZIP Codes] Z1
left outer join [ZIP Codes] Z2 on (Z2.[ZIP Code]='94558')
order by 4

Note here that the data as presented in the Access table stores the latitudes and longitudes as text, so we need to use cast to force it to floats. This gives us a result set that looks a lot like this...



Monday, November 2, 2009

Using a Legacy Windows DLL in ASP.NET

Recently I had to use a very old DLL in an ASP.net web site. The dll has one function (that I care about) and I went down one rabbit trail after another looking for how to get this done. This is NOT a .NET managed dll, it's an old-style dll where there is a function that accepts various parameters and returns a horrible coded string.

Without much ado, let me show you what worked in this case. Note that Visual Web Developer was of NO HELP AT ALL when it came to figuring out the setup for this.

Place the dll. I found that it was nearly impossible to place the dll in my /bin/ directory under my website. Likewise I found that it was impossible to create a reference to it in the /bin/ directory. I placed the dll in my C:\Windows\System32\ directory. I have seen some chatter that this is the only place the IIS server has enough permissions for, so even if you think someplace else might be better, I'm telling you that this worked for me.

Wrap the function. You need to create a wrapper in your c# code to call the function in the dll. Note that you MUST have the function call specs - VWD will not find them for you like it will for a .NET managed dll.
Here's what the setup looks like... anything highlighted will have to be replaced with the info for your dll call.


using System;
using System.Runtime.InteropServices;

/// 
/// Wrapper for a function in the CodeGen DLL
/// 
public class CodeGen
{
 [DllImport("codegen.dll")]
 public static extern string CreateCode2(
  int level,
  string name,
  string encrypt_template,
  Int64 hardwareID,
  int otherinfo1,
  int otherinfo2,
  int otherinfo3,
  int otherinfo4,
  int otherinfo5
  );
}

Now you just add a call to your wrapper function from wherever it's appropriate.


 protected void Page_Load(object sender, EventArgs e)
 {
  string code = CodeGen.CreateCode2(1, 
     "Bob", 
     "This is an encrypting template", 
     0xface0fff, 0, 0, 0, 0, 0);
  Label1.Text=code;
 }

Wednesday, October 28, 2009

Using GenericIdentity for Cross Platform Authentication in the .NET framework

Let me say from the beginning that this should be a lot easier.

Basic Authentication

When designing a WinForms application, the most straightforward way to authenticate a user is using NTLM or Active Directory... It's built right into the OS and you don't need to deal with password dialogs and lost password questions at all - just ask Windows who the user is, like this...

using System.Security.Principal;
...
WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();

That was easy... now how about using a web application?  That gets a little more complicated.  If the user is coming in over the intranet, then IIS knows who it is, but if they are accessing your site over the internet, it uses the whole aspnet security setup to create users and roles and permissions.  This is very easy to use as well, and for the most part requires no coding at all - but if you need to retrieve the name of the authenticated user, you would use something like this...

using System.Web.Security;
...
MembershipUser User = Membership.GetUser();
roles = System.Web.Security.Roles.GetRolesForUser();

Rolling Your Own

What if you need a robust set of libraries that can access identity information regardless of the data source?  Thats where the GenericIdentity and GenericPrincipal objects come into play.
For deployment into a mixed web/winforms environment, these components are very useful as they can migrate without regard to the source of the user and role data.

Creating a Generic Identity

...empty

string userName = "somebody";
GenericIdentity authenticatedGenericIdentity = new GenericIdentity(userName, "Database");

This creates a generic identity named somebody who was validated using an authenticacationType of "Database".

...from Windows

WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent();
string authenticationType = windowsIdentity.AuthenticationType;
string userName = windowsIdentity.Name;
GenericIdentity authenticatedGenericIdentity = new GenericIdentity(userName, authenticationType);

...from a database

string connectionstring = @"Data Source=.\SQLExpress;Initial Catalog=PermsLib;Integrated Security=True";
SqlConnection MyConn = new SqlConnection(connectionstring);
MyConn.Open();

SqlCommand Query1 = new SqlCommand(@"Select * from logins where username=@user and password=@pwd and account_locked=0;", MyConn);
Query1.Parameters.AddWithValue("@user", username);
Query1.Parameters.AddWithValue("@pwd", password);

SqlDataReader myReader = Query1.ExecuteReader();

if (myReader.HasRows)
{
string userName = username;
GenericIdentity authenticatedGenericIdentity = new GenericIdentity(userName, "Database");
return authenticatedGenericIdentity;
} else {
throw new System.Security.SecurityException("invalid user");
}

The great thing is that you can toss these objects around in a mixed application, and they will travel nicely from place to place.

What is a GenericPrincipal?

That explains the identity object, but what is a GenericPrincipal?
As far as I can tell the Generic principal's only use is to contain both a GenericIdentity object, and a list of roles assigned to that identity.  So think of it as a baggie with an ID card and a ring of keys (roles/permissions).
Loading a GenericPrincipal  object is easy, all you need is a GenericIdentity, and a string array of roles.
string[] userRoles = { "Administrator", "Manager" }; GenericPrincipal MyPrincipal = new GenericPrincipal(userIdentity, userRoles);
The source of the roles data is unimportant, it can be hard coded, from a database, XML, or even read directly from ActiveDirectory sources.

Thursday, September 17, 2009

Failed to access the metabase, error code is 80070422

Event Type: Error
Event Source: MSExchangeMU
Event Category: General 
Event ID: 1009
Date:  9/17/2009
Time:  9:51:51 PM
User:  N/A
Computer: WEB1
Description:
Failed to access the metabase, error code is 80070422 (The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.). 

For more information, click http://www.microsoft.com/contentredirect.asp.

It seems that the latest Windows 2003 SBS patch (which I think was a IMF Patch) causes the IIS Admin Service to switch from Automatic Startup to DISABLED. Turn it back to automatic, and start it if you ever want to check your email again.

Thursday, July 16, 2009

7q89dbtmhi

7q89dbtmhi

Monday, February 23, 2009

Connection Strings, Web.Config, and the Development Environment

Ok, admittedly it's not as enticing as Sex, Lies, and Video Tape, but this is an awesome way of helping you with ASP.NET website development.

The Problem

You create a site on your local machine(s) and get it working perfectly. Now it comes time to publish your changes to the live website, and you run into a giant problem whenever there are any changes to your web.config file. All your connectionstrings (Data Source=localhost\SQLEXPRESS;Initial Catalog=myDB;Integrated Security=True) and configurations get promoted to the live site, where they fail until they are hand-edited to reflect the web site's configuration. Alternately, you can forbid the publishing of web.config, forcing all changes to this one file to be done by hand.

Following is a procedure showing how to remove the appSettings and connectionStrings sections into a separate file, enabling the publishing of web.config whenever without hand-editing.

  1. with your project open, add a new item (control-shift-A).
  2. choose Web Configuration File and name it appsettings.config Ignore the text that Visual Web Developer automatically puts in there.
  3. create another one named connectionstrings.config.
  4. wipe the text from these 2 new files.
  5. copy the appSettings section from your web.config appSettings section into the appsettings.config file. It should look like this:
    <appSettings>
    <add key="connectionstring" value="Data Source=localhost\SQLEXPRESS;Initial Catalog=myDB;Integrated Security=True"/>
    </appSettings>
  6. now do the same for connectionstrings:
    <connectionStrings >
    <add name="ConnectionString" connectionString="Data Source=localhost\SQLEXPRESS;Initial Catalog=myDB;Integrated Security=True"   providerName="System.Data.SqlClient"/>
    </connectionStrings>
  7. Now replace these sections only in your web.config file as follows:
    
    <appSettings configSource="appsettings.config"> </appSettings>
    <connectionStrings configSource="connectionstrings.config"> </connectionStrings>
  8. Note: if anyone knows how to tell the Copy Web Site dialog to NEVER publish these files, I am all ears.

Now you can hand-edit the web server's copy of appSettings.config and connectionstrings.config to give them the correct environment for the webserver. If you can't edit these remotely, then you can edit them on the development server, publish them and then change them back for your development environment.

Monday, February 2, 2009

"Server Application Unavailable"

I got this error message while trying to set up my on line site to use a different database from the default crap-tastic AspNetSqlProvider that takes 3 minutes to boot up with each web hit.
Here's the entire (incorrect) error message as IIS sends it.

Server Application Unavailable

The web application you are attempting to access on this web server is currently unavailable.  Please hit the "Refresh" button in your web browser to retry your request.
Administrator Note: An error message detailing the cause of this specific request failure can be found in the application event log of the web server. Please review this log entry to discover what caused this error to occur.
The first clue I got that something was Micro-softy was that there was no event logged in the event logger. I think I may have caused this problem when I logged in to the server with Remote Desktop and with Visual Web Developer at the same time, trying to make it select the correct database.

The Solution

  1. go to the webserver (or remote-desktop in)
  2. open IIS Manager (Microsoft Internet Information Services)
  3. browse to the server and website that is broken
  4. stop the website
  5. open the site's properties page (right click the name of the site and pick "properties")
  6. select the ASP.NET tab and change the .net version. Click Apply.
  7. change the version back to the right (latest) version. Click Apply.
  8. close the properties page and restart the website.

Thursday, January 22, 2009

Oracle Retentive

Oracle Retentive: adj. 1. The inability to write even the most trivial software function without making it access a SQL database in general, or an Oracle database in particular. Sundar is so Oracle retentive I bet he couldn't write "Hello, World" without a database connection. 2. The inability to understand any database other than Oracle, say MSSQL or MySQL. 3. The propensity to hand large sums of cash to Oracle because they asked you for it.

Thursday, January 15, 2009

View. Print. Handheld. Make your site work on any media.

There is no need to manually control the rendering of your site to alter layout. There is an easy CSS based feature that can be used to format your entire site for whatever options you need.

In this article we will see how to make the same site render automatically for screen, print, and hand held. There are other media types that can be used, but these will be the most common for daily use.

Wouldn't it be great if you could just alter the stylesheet for your site to adjust it slightly for printing or hand held devices? Then you could just create a single site, and use a modified stylesheet based on the media the site is being viewed on. Well, wishes do come true... observe!

<link href = "mysite.css" rel="stylesheet" type="text/css" media="screen" />
<link href = "mysite.print.css" rel="stylesheet" type="text/css" media="print"/>
<link href = "mysite.pda.css" rel="stylesheet" type="text/css" media="handheld"/>

All 3 lines (or ones like them) are placed in the <head> section of the master page, or in every html page if you are not using a master page. Note the normal html link to the stylesheet, with the addition of the media parameter. These media types are pre-defined and can be selected from a drop down in Visual Web Developer. The current list of supported types is here.

Now we can load a different stylesheet based on our needs! The next thing to do is to make a copy of our existing full stylesheet. If you do a lot of in-page formatting, you are going to rue the day you decided to do that.

Making the Menu Disappear

To make any div simply cease to exist on a printed page, simply do this in the printer version of the stylesheet:

#graybar{display:none;}
#menubar{display:none;}

The display:none; means that this div or td (tablecell) will not be rendered when the browser is rendering to that media type - print in this case. so our entire graybar object is hidden.needless to say, your layout can be dramatically altered for smaller handheld displays.

The most brilliant thing is that the browser manages all this. So you never have to do anything conditional in your code that eats processor power. For instance, you don't have to have a "printer-friendly" version, the print engine will automatically choose the stylesheet intended for paper printouts. What's really cool is that you needn't worry what happens if you have a printer-friendly version of your site and people start navigating around - or linking to the version not intended for screen.

Layout for paper

OK, in word processors we taught ourselves to think in "points". then we started doing websites, and points make it all unmanageable, we opt instead for "pixels". But now we're actually designing websites for a paper media, so in the copy of the stylesheet, wherever you see the letters px, it's a good idea to re-arrange your thinking back into points. It can be a lot of work but you'll thank me later.

Tuesday, January 6, 2009

Don't Overlook Robots.txt

In the good old days, web spiders would crawl your sites once you registered them with a search engine. Today, they are a lot more proactive, crawling sites when the domain names are registered. For this reason, it is not optional during the development phase to add a robots.txt file to all projects that instructs robots not to crawl the site.

It's super easy. Just create a text file in the website root directory named robots.txt. Put the following text in it.

User-agent: *
Disallow: /

That's it. Now your temporary website is safe from most webcrawlers. Note that all subdomains must have one of these in the root path.

Examples:

http://www.mysite.com
http://demo.mysite.com
http://admin.mysite.com

There is no need to put a robots.txt in subdirectories or virtual paths, such as

http://www.mysite.com/admin
http://www.mysite.com/users

More info on Robots.txt here http://www.robotstxt.org/

More in-depth info here http://en.wikipedia.org/wiki/Robots.txt

A tutorial for when you want your site to be crawled. http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=40360

Please note that without a robots.txt file, a web spider will attempt to crawl every file, every path in your website. It is rare that you would actually want a webcrawler to do this. For instance, do you really want all your button images and background images indexed?

Saturday, August 30, 2008

Use Tables, not CSS

The following 2 shots are of Firefox and IE, and they illustrate how designing layouts with CSS (div tags with style sheets positioned to produce a column or flow layout) DOES NOT WORK the same way in all browsers.

CSS for layout sounded like a great idea, it just didn't deliver on it's promises. Tables do.


This is Firefox fucking up my CSS layout.


To my understanding of CSS, this is how it should look - how it does look in IE.

Wednesday, August 27, 2008

The Comprehensive ASP.NET Development Checklist

The point of this post is not that it is a comprehensive checklist, but rather that it will become one. I mostly write it because I got tired of skipping the same old steps every freaking time I created a new website. So without further ado, here is the list.
  • APPLICATION NAME: Will your application require it's own app name? if so, create it on your web server NOW. This will simplify the whole authentication thing if you're using ASP.NET authentication.
  • MEMBERSHIP AND ROLES PROVIDERS: - if you are using them check here for info on doing this. In general you do not want to use a site database, they are way too slow.
  • SETUP SITE DEFAULTS: Use the App Config screens to assign an email account to your web server. Verify that this works with AO-Hell!
  • PAGE TITLES: Make sure every aspx page has a title.
  • favicon.ico: Make sure your site has a 16x16 icon. These can alternately be loaded in the page's headers if you need different icons for each page.
  •  SSL Certificates (optional)
  • Turn off Debug Mode
  • Lock-down your Administration site
  • Review robots.txt
  • table CSS to table-layout: fixed; (if you don't want your tables expanding on you)

Monday, August 25, 2008

Windows XP: Service Pack 3

...Sucks.

Before this critical patch I would leave my computer going 24/7 for weeks without problems. I have Carbonite and I like to let it do it's backups all night long.

But since the upgrade, I have to reboot 3 times a day AND I come in every morning to find that my Internet connection has frozen up. I would call Microsoft to complain, but I don't have $450 to spend on a service call.

I can feel the Linux adrenaline building in my bloodstream.

Share This!

Contact Us

Name

Email *

Message *