Rolling SQL Server Error Logs WITHOUT Rebooting

17 04 2008

This is a bit in reverse as the code will be above the rant today. ;)

To roll SQL Server Error Logs, in 2000 and higher, a reboot isn’t necessary. 

Simply open up the Management Console (or Query Analyzer) and attach to the Master database.  From there, execute the built-in stored procedure ‘sp_cycle_errorlog’.

exec sp_cycle_errorlog
GO

This will roll your current ERRORLOG file along, according to the configuration settings you’ve specified.  The current log will be renamed ERRORLOG.#.

<rant>

We had a… discussion… earlier today between the department I work in and another regarding the virtues of uptime and keeping servers available. 

The paradigm is to reboot a server when something happens—no matter what.  Troubleshoot? Nah.  Diagnose?  No way.  Just kick it and pray it works.  Why?  Because that’s how Windows works.

Now, I agree with that 100%.  That is how Windows works.  I do that at home.  If my home computer starts being stupid, I’ll reboot it as a first step and go from there.

But, my home computer isn’t in a production environment with thousands of users (that I’m aware of).

There’s a big different there.

</rant>

 





SQL Server 2005: Stored Procedures Executor Role

7 04 2008

Granting permissions to use stored procedures is something I rarely do… in most of my applications, I either use .NET SQL projects and compile my SQL code OR everything is handled in the data layer/LINQ code.

We’ve had a recent consult project and the coders use stored procedures heavily.  That’s cool—to each their own.  Performance seems good on the system and the procedures are pretty small.

But… remembering to readd the EXECUTE permission to the user account on each reload is REALLY annoying.  I’d read this somewhere (if I can find the original source, I’ll cite it) ages ago and dragged it out of the code library.  A quick bit of TSQL code to create a database role that SHOULD exist out of the box—one that can execute stored procedures.

/* Create a new role for executing stored

   procedures */

CREATE ROLE db_executor

 

/* Grant stored procedure execute rights

   to the role */

GRANT EXECUTE TO db_executor

 

/* Add a user to the db_executor role */

EXEC sp_addrolemember ‘db_executor’, ‘AccountName’

Quite easy and it makes it VERY easy to control EXECUTE permissions for your accounts.





Using Generics to Update DataBoundControls - A Prototype

24 03 2008

NOTE: This is a prototype, an idea, a random thought expressed aloud (well, in type).  The code explains a concept and isn’t “tested” or production worthy (in my opinion). 

Feedback is always appreciated. :)  This is also what happens when I have a week off work and come back with ‘ideas.’

I find that a few of my projects, like the WebGallery2, all have a similar functionality.  On pages with GridViews, ListViews (which, I’m slowly replacing all my GridViews with), or other DataBoundControls, I follow a common theme for data binding:

If the data set will be cached or in session, is that session/cache null OR has the data set been explicitly modified?

  1. true – regenerate the data set and repopulate session/cache.
  2. false – read the current data set from session/cache to the control.

In a single instance, the code to do this might look like:

private void BindList(bool hasBeenModified, string sessionVariable)

{

       // If our session variable is null or the data has

// been explicitly modified, then rebuild the session variable.

if (Session[sessionVariable] == null || hasBeenModified)

              Session[sessionVariable] =

db.GetWebFilesByGalleryName(this.Id);

 

resultsListView.DataSource =

Session[sessionVariable] as List<WebFile>;

 

resultsListView.DataBind();

}

This would then be called with:

BindList(true, “CurrentGallery”);

However, this code really bothers me. 

The data source (the db.GetWebFilesByGalleryName method), data bound control (the resultsListView), and the type of the data source (List<WebFile&gt ;) are all hard coded.

How could this helper method use generics to add a bit of resuability?  What about when I want to use a GridView instead of a ListView, or have a List<Gallery>, List<String>, string[] of information?

First Attempt

The first attempt works.  It takes the generics as anticipated and is rather easy to use.

protected void BindDataControl<TDataControlType, TEnumerableType>

(bool hasBeenModified, string sessionVariable,

              TDataControlType dataControl, TEnumerableType dataSource)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable

{

// Add the dataSource to session.

       if (Session[sessionVariable] == null || hasBeenModified)

              Session.Add(sessionVariable, dataSource);

 

// Read the data from session and bind the data control.

       dataControl.DataSource =

(TEnumerableType)Session[sessionVariable];

       dataControl.DataBind();

}

The constructor here has both generic parameters and standard parameters.

  • TDataControlType has a generic constraint that requires it to be part of or a subclass of DataBoundControl (GridView, ListView, etc).
  • TEnumerableType requires the source to inherit from IEnumerable (List, Array, etc).

Here are a few examples of using it this bit of code:

var gv = new GridView();

this.Page.Controls.Add(gv);

BindDataControl<GridView, Array>(

true,   // this is new, so build a session variable.

       “test”, // the session variable

       gv,     // the Id of our GridView

       new[]   // The data source, an array.

              { “hello”, “world” });

When rendered, we have a simple GridView with our two data items.

GridView and Array data source.

What about a more complicated example using collections and a ListView? On the current build of the WebStorage2 project, the galleries are built in a similar method (see this post for more details).  I could just as easily replace the logic in Show.aspx’s Page_PreRender with:

BindDataControl<ListView, List<WebFile>>(

true,

       “CurrentGallery”,

       lv,

       db.GetWebFilesByGalleryName(Request.QueryString["id"]));

So what’s the downfall to this method? 

Downfall #1: It’s a performance nightmare. AFAIK, when passing a method (which GetWebFilesByGalleryName is a method from my LINQ DataContext), it is evaluated immediately.  So, with that in mind, the hasBeenModified is irrelevant—it may not NEED to update the session, but the method will still go out, search the database, and return the results.  That’s a bad deal.

What I don’t know and am not sure how to check is whether or not the lazy/delayed loading in LINQ would balance out this at all.  Ideas?

Second Attempt

The second attempt adds in a bit more “generic” and a lot more reflective.  By adding a reference to System.Reflection, we can simply pass a string reference to a “builder” method rather than the method it self—thus saving the prefabrication of the data source when it’s not really needed.

protected void BindDataControl<TDataControlType, TEnumerableType>

(bool hasBeenModified,

              string sessionVariable,

             TDataControlType dataControl,

             string dataSourceMethod)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable

{

// If session is null or has been modified (thus invalidated),

       // update the session state.

       if (Session[sessionVariable] == null || hasBeenModified)

       {

              // Invoke the specified method that

// creates our data source.

             var data = Page.GetType().InvokeMember(

dataSourceMethod,.

BindingFlags.InvokeMethod |

                    BindingFlags.NonPublic |

                    BindingFlags.Instance,

                    null, this, null);

 

// Add it to session.

             Session.Add(sessionVariable, data);

}

 

// Read the data from session and bind the data control.

       dataControl.DataSource =

(TEnumerableType)Session[sessionVariable];

      

dataControl.DataBind();

}

In this method, the Page.GetType().InvokeMember method iterates through the methods on the page, finds the one that matches the string name passed to it, and executes it. 

Then, with our “data” results, the rest is the same as the previous method.

Unfortunately, I cannot pass the LINQ direct lookup anymore because the scope of InvokeMember is limited to the calling page.  I’ll need to create another little method, called GetResults in this case, to do the query for me.

protected List<WebFile> GetResults()

{

return db.GetWebFilesByGalleryName(Request.QueryString["id"]);

}

And the updated BindDataControl method:

BindDataControl<ListView, List<WebFile>>(
  false,
  “CurrentGallery”,
  lv,
  “GetResults”);

Now, since our constructor does not contain the method to fetch our data, simply a string, the results are not refetched each time the method is called—only when the requirements are met further in the code.

Downfall #1: This method requires an additional “helper” method on every page to fetch the data.  You can’t access methods outside of the page—or can you?

Downfall #2: What happens if you need to pass parameters to your InvokeMember?  You CAN, but the syntax is nasty and becomes even more difficult if the parameters are not always in the same order (which doubtfully they would be if you’re using generics).

Third Attempt

The third attempt looks more like the signature from Hell than a real method.  There had to be a way around the “stuck on this page” snafu with the second attempt… and there was, by specifying the class too using a generic.

protected void BindDataControl

<TDataControlType, TEnumerableType, TDataSourceClass>

(bool hasBeenModified, string sessionVariable,

              TDataControlType dataControl,

string dataSourceMethod,

TDataSourceClass dataSourceClass)

where TDataControlType : DataBoundControl,

              new() where TEnumerableType : IEnumerable,

             new() where TDataSourceClass : class

{

// If session is null or has been modified

// (thus invalidated), update the session state.

       if (Session[sessionVariable] == null || hasBeenModified)

       {

              // Invoke the specified method that

// creates our data source.

             var data = dataSourceClass.GetType().InvokeMember(

dataSourceMethod,

                     BindingFlags.InvokeMethod |

                    BindingFlags.NonPublic |

                    BindingFlags.Public |

                    BindingFlags.Instance,

                    null, dataSourceClass, null);

 

// Add it to session.

Session.Add(sessionVariable, data);

}

 

// Read the data from session and bind the data control.

dataControl.DataSource =  

(TEnumerableType)Session[sessionVariable];

 

dataControl.DataBind();

}

Good grief. 

This method adds a third generic to the constructor—TDataSourceClass—as well as the additional constraint requirement.  I’ve also added an additional BindingFlag—Public—since most of the methods in LINQ DataContext classes are decorated public.

Rather than pulling from this.Page, we’re now calling InvokeMember from the parameter class and returning the results to the calling page.  There’s one other change—rather than looking at “this” as the Binder parameter, we’re referencing the class passed along in the constructor—the dataSourceClass.

BindDataControl<ListView, List<WebFile>, WebGalleryDataContext>(
    true,
    “CurrentGallery”,
    lv,
    “GetWebFiles”,
    db);

Here we have two additional parameters, the generic parameter, TDataSourceClass, that I’ve passed the LINQ Data Context into to define the Type of the dataSourceClass parameter passed later in the constructor. 

“Verbalized”, the method’s generics read: BindDataControl to a ListView with the expected data format of a List<WebFile> using the WebGalleryDataContext class. 

The parameters (which could be reordered to make better sense) read: the data is new or has changed, so store the results in “CurrentGallery” and return them to ‘lv’ (the ListView object on the web form).  Fetch the data with GetWebFiles from the instance of db (the WebGalleryDataContext object instanciated previously in the page).

Downfall #1: Methods are still required—you cannot pass a simple data source to the BindDataControl method.

Downfall #2: Additional coding on the BindDataControl methods required to handle parameters.

This third attempt handles our most complex request—but what about the original “hello”/”world” array request?  It can be done, but, as previously mentioned, requires extracting the array list outside of the method constructor.

 

protected void Page_Load(object sender, EventArgs e)

{

var gv = new GridView();

       this.Page.Controls.Add(gv);

 

BindDataControl<GridView, ArrayList, Page>(

true, “junk”, gv, “Get”, this.Page);    

}

 

protected ArrayList Get()

{

return new ArrayList {“hello”, “world”};

}

To reference methods that exist in the same code-behind page, this.Page and the Page class offer the correct class access.

So, is this the best way to do it?  Probably not!  How would you tidy this up or rewrite it?  I’m interested!





Windows Server 2008 hits MSDN Downloads

7 02 2008

Windows Server 2008The “heroes” campaign is fully underway with just 20 days left untilt he “official” release of Visual Studio 2008, SQL Server 2008, and Windows Server 2008.

I haven’t spent a lot of time with Server 2008 beyond messing with HyperV, but I was quite impressed.  Being the VM freak that I am, (basically) building Virtual Server into the operating system and beefing it up has huge appeal to me. 

For more information about Windows Server 2008, check out the MSFT Learning Portal.

If you’re a MSDN subscriber, the downloads are available in both the Top Subscriber Downloads and the standard (slow) MSDN library.  One thing to note, Windows Server 2008 has a different licensing scheme than previous operating systems—we’re limited (at first glance) to 1500 activations.  I can’t fathom NEEDING that many, but when I think of creating and blowing away virtual machines in our development lab, it makes me wonder…

 





Migrating SharePoint 2003 without SPSBackup

1 11 2007

The title of this post may not be totally accurate.  It could also be:

  • Migrating SharePoint 2003 from a Single to Farm environment.
  • Migrating SharePoint 2003 by Restoring the Portal
  • Migrating SharePoint 2003 through SQL Server.

or, my favorite:

  • Migrating SharePoint 2003 when the SharePoint Gods are angry with you.

There are numerous factors that come into play when trying to migrate SharePoint 2003.

  • Versions and subversions of SharePoint,
  • Versions and subversions of Windows Server,
  • Versions and subversions of SQL Server 2005,
  • Deployment hierarchy
  • and number of “Unexpected errors” that can occur for no real reason.

After a few days of battling topologies, obscure messages in SPSBackup, and service packs, I finally just installed clean copies of SharePoint 2003 on each of the servers; upgraded to the latest service packs, and tried a different approach—using SQL Server backups.

Backing Up

  1. Backup the “to be” migrated SharePoint databases (I had a SITE, PROF, and SERV database) to three separate .BAK files.
  2. Copy those files to your new SQL Server and restore them as SITE_Old, etc.
  3. The ConfigDb database is unnecessary.

Restoring the Portal

  1. When you’re first presented with the SharePoint Central Administrator, complete the service account information, server topology, etc.  This will recreate the ConfigDb for your new portal server.
  2. When creating a portal, change the radio button from ‘Create a portal’ to ‘Restore a portal’.
  3. You’ll be prompted for three database names: your site, user profile, and services.  Enter the names you gave them (SITE_Old, etc) from “Backing Up” Step #2.
  4. Specify your Portal’s URL and click OK.

That’s it; it’ll churn for a few minutes and recreate the portal.  If you are in a farm with multiple web servers, make sure you’ve recreated all necessary files, web parts, etc. on each server.

 





Enterprise Library and Oracle Stored Procedure Record Sets

27 08 2007

Perhaps I just don’t sacrifice enough innocents to Oracle daily to keep up on the odd things regarding Enterprise Library and Oracle.  Or, I’m just very lucky to have most of my projects based on Microsoft SQL Server and just expect things to work just as easily with Oracle.

So what about returning a record set in Oracle?  It requires an output cursor.  Unlike tSQL, you can’t simply write a SQL command that “SELECT * FROM Customers” and expect a dataset to be returned.  You have to associate it to a cursor and then use the Oracle type called “ref cursor” to access it.

If I was not using Enterprise Library, I could use an Oracle Connection or ODP.NET to access the OracleType.Cursor.  Unfortunately, for now at least, I want to use the default OracleClient and I want to avoid hacking the Enterprise Library (Ref #1).

On our Oracle side, let’s create a simple aggregation query that I was working on earlier that accepts three input variables: quarter, year (stored as a string ), and the identifier for the teacher.  It also has one output variable, which we’ll call resultset_out of type Types.cursorType (Ref #2).

CREATE OR REPLACE PROCEDURE GetMathData
( quarter_in IN NUMBER,
  year_in IN VARCHAR,
  sin_in IN NUMBER,
  resultset_out out TYPES.cursorType)  AS BEGIN

OPEN resultset_out FOR
SELECT
    pupil_id as StudentId,
    teacher_id as TeacherId,
    report_id,
    nvl((select ‘true’ from dual where
      question_val(pupil_id, 143, r.quarter, r.year) = ‘true’ and 
      question_val(pupil_id, 152, r.quarter, r.year) = ‘true’), ‘false’) as Rep10,
    question_val(pupil_id, 94, r.quarter, r.year) as PatternAB,
    question_val(pupil_id, 95, r.quarter, r.year) as PatternABC,
    question_val(pupil_id, 96, r.quarter, r.year) as PatternAAB,
    question_val(pupil_id, 97, r.quarter, r.year) as PatternAABB
  FROM Reports r
  WHERE r.TEACHER_ID = sin_in
    AND r.YEAR = year_in
    AND r.QUARTER = quarter_in;

END GetMathData;

From first glance, that looks fine, but there’s nothing returned.  To access our result set, we have to echo it back out using PRINT.

variable resultSet refcursor;
exec GETCIPMATHDATA(4, ‘2006-2007′, [somenumber], :resultSet);
print :resultSet;

Now that we have that taken care of, let’s use it in Enterprise Library.  Be sure to import .Data and .Common.

Database db =

DatabaseFactory.CreateDatabase(“OraDatabase”);

 

DbCommand cmd =

db.GetStoredProcCommand(“GetMathData”,

4,

“2006-2007″,

[somenumber]);

 

DataTable dt =

db.ExecuteDataSet(cmd).Tables[0];

 

GridView gv = new GridView();

gv.DataSource = dt;

gv.DataBind();

Unfortunately, this will fail.  We’re only passing three variables, not the four (the refcursor) needed.  Enterprise Library (as of 3.1 May 2007) doesn’t have a DbType for Cursor (similar to the OracleType.Cursor part of System.Data.OracleClient). 

To get it to compile, our Stored Procedure needs one more parameter.   What it needs, after trial and error, it simply a pacifier.  Placing null as the recipient of the refcursor parameter keeps it happy and compiles.

 

DbCommand cmd =

db.GetStoredProcCommand(“GetMathData”,

4,

“2006-2007″,

[somenumber],

null);

 

So, you may be wondering where the data comes from… since we’re never handling the refcursor.  From what I’ve found (which isn’t much), if you are using ExecuteDataSet, the first output cursor (resultset_out out TYPES.cursorType) that is named with “_out” will become the returned DataSet.  The fact it worked had nothing to do with technology and all to do with my variable name.  *sigh*  Also, as pointed out in Tim Hollandar’s blog, this limits you to retrieving only the “_out” cursor… and only one.

 

After all that fun, I think I’ll walk into the back room and hug the SQL Server.

 

Ref #1: For an excellent article on hacking Enterprise Library to work with ODP.NET, check out Alex’s post out on CodeProject.  Looks good and I’m sure it works—just not something I want to get into the habit of right now EVERY TIME ODP or EntLibrary updates.  Seriously though, this stuff should work out of the box. *coughEntLibTeam!cough*

 

Ref #2 : This is a custom package definition that holds the ref cursor type.  I added it using:

CREATE OR REPLACE PACKAGE Types AS
     TYPE cursorType IS REF CURSOR;
END Types;





SQL Server 2005 - Importing from a Flat File

23 07 2007

With our recent renumbering of every pupil in our district, several applications had to have keys updated.  Good times.  Unfortunately, our student information is on Oracle and my information is on SQL Server.  Rather than bother with creating links and such, a simple import of a two column (old, new) text file and a couple update statements made the process very painless.

Well… maybe.

Upon running the script, it failed on Validating with:

Validating (Error) Messages

  • Error 0xc00470fe: Data Flow Task: The product level is insufficient for component “Source - import_txt” (1).  (SQL Server Import and Export Wizard)
  • Error 0xc00470fe: Data Flow Task: The product level is insufficient for component “Data Conversion” (35).  (SQL Server Import and Export Wizard)

Ehh…

So, I did the usual—Googled it.  I found many resources:

  • Is SSIS installed?  Yes.
  • Is Integration Services (ehh, isn’t that SSIS?) installed?  Yes.
  • Is SP1 installed?  Yeah, SP2!

Everything sounds good… so what’s the catch?

The catch was where I was RUNNING it from.  The server had SSIS installed—the WORKSTATION did not.  I just run the Client tools.  Unfortunately, according to http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=112469&SiteID=1, the SSIS is required no matter what.  It says that SP1 fixed this, but… that doesn’t seem to be the case (in this situation).

I moved my text file off to the server and ran it there and it worked like a champ.  *grumble*

So, I’m, for now, tossing the Developer tools on my workstation to dink with and see if that solves the problem… and then hunt down the Microsoftie that didn’t ensure that a simple Import/Export can work flawlessly from the client tools.





Release date for VS2008, SQL2008, and Windows Server 2008 Announced!

13 07 2007

Soma announced this morning (bright and early at 2:13 AM!) the official dates for Server, VS, and SQL 2008’s launch dates.

During Tuesday’s kickoff our COO Kevin Turner announced that the company will be jointly launching Windows Server 2008, Visual Studio 2008 and SQL Server 2008 in Los Angeles on February 27, 2008.   As the most important enterprise launch in the company history, February 27 will kick off a “launch wave” of hundreds of events that Microsoft will host worldwide. 

Source: http://blogs.msdn.com/somasegar/archive/2007/07/13/it-all-begins-february-27th.aspx

That’s actually later than I expected; I was hoping for a 2007 date, but…

[Update 15 July 2007:  From Doug Seven, the VSTS Sr. Product Manager:

While the launch events are scheduled to kick off on February 27, 2008, Visual Studio 2008 will be released before the end of the year. 

Rejoice!]





Merging Different DataSources - Old and LINQ Ways

2 07 2007

Recently, I had to come up with a way to do lookups from an existing application (with data in a SQL Server 2005 base) to our primary database (an Oracle 10g base).  If these were in the same database, or even same server, you could join the tables and things would be pretty easy.  Unfortunately, this took two steps, but turned out to not be so bad.

Here’s an example.  Note, I’m using the Enterprise Library for pull the data down, but the true example is independent of that—feel free to use whatever connection you feel fit to use.

Database dbSandbox = DatabaseFactory.CreateDatabase(“Sandbox”);

 

string sqlSandbox = “SELECT COUNT(r.RecordId) as Count, r.DepartmentId “ +

“FROM ExceptionRecords r “ +

                  “WHERE Year = @Year “ +

                  “GROUP BY r.DepartmentId “ +

                  “ORDER BY r.DepartmentId”;

 

DbCommand cmdSandbox = dbSandbox.GetSqlStringCommand(sqlSandbox);

db.AddInParameter(cmdSandbox, “Year”, DbType.Int32, 2006);

 

DataTable dtSandbox = dbSandbox.ExecuteDataSet(cmd).Tables[0];

Now we have a DataTable object that contains our information.  However, while we have the DepartmentId, we need the Department Name for our report.  That information is not located anywhere within the SQL Server database because the application is using our standard framework to get that information at runtime.

So, let’s add a new string column to our DataTable to hold the Department name.

dtSandbox.Columns.Add(new DataColumn(“DepartmentName”, typeof (string)));

Now, we’re ready to loop through and populate that new column.

foreach (DataRow row in dtSandbox.Rows)

{

row["DepartmentName"] = Depts.GetDept(Convert.ToInt32(row["DepartmentId"])).Name;

}

We’re now free to use this DataTable for our report or add additional columns/calculations to it.

Now, what if we wanted to get a bit crazy and use LINQ instead of standard T/SQL?

SBDataContext db = new SBDataContext();

var records = from r in db.ExceptionRecords

where r.Year == 2006

orderby r.DepartmentId ascending

group r by r.DepartmentId into g

select new {

DepartmentId = g.Key,

Count = g.Count() };

So, we’ve now got a var object that contains our grouped information.  The group statement in LINQ basically says: take the information you have in “r” and group it by a column, in this case DepartmentId, and place that into a new object, called [g] (for group, for sake of simplicity).  Afterwards, we created a new var object (to be placed into records) that consisted of the grouping key (which was the DepartmentId) and a count by each DepartmentId.

For the SQL inclined, we’ll notice that the statement looks similar to our one above:

SELECT [t1].[DepartmentId], [t1].[value] AS [Count]
FROM (SELECT COUNT(*) AS [value], [t0].[ DepartmentId]
FROM [ExceptionRecords] AS [t0]
WHERE [t0].[Year] = @p0
GROUP BY [t0].[ DepartmentId]) AS [t1]

Now, we must place the DepartmentName with the record.  If we simply wanted to write it out, we could do something like:

foreach (var c in records)

{

Response.Write(String.Format(“{0} ({1}) - {2}<br/>”,

Depts.GetDept(c.DepartmentId).Name,

c.DepartmentId,

c.Count));

}

Or we could create a DataTable (since GetDataTable() has unfortunately disappeared from the current LINQ release; hopeful that it will make it’s return along with the LinqDataSource in Beta2):

DataTable dt = new DataTable();

dt.Columns.Add(new DataColumn(“Count”, typeof (Int32)));

dt.Columns.Add(new DataColumn(“DepartmentId”, typeof(Int32)));

dt.Columns.Add(new DataColumn(“DepartmentName”, typeof(string)));

 

foreach (var c in records)

{

DataRow dr = dt.NewRow();

dr["Count"] = c.Count;

dr["DepartmentId"] = c.DepartmentId;

dr["DepartmentName"] = Depts.GetDept(c.DepartmentId).Name;

dt.Rows.Add(dr);

}

Is one better than the other?  Ehh… the TSQL solution is quick, painless, and using Enterprise Library, relatively standard to support.  The LINQ solution requires almost no TSQL knowledge, allows everything to be handled by the application, but is a bit bumpy if you’re wanting to populate anything that doesn’t understand the var object.  Going from Data -> DataTable is a LOT less code than with LINQ, but eventually, perhaps, that won’t even be necessary.

 





Hosting Provider — Your suggestions?

14 06 2007

I’ve had the outs with WebHost4Life on providing hosting for the prototype sites that I create (and… the photo sites… we’ll see how long the photos remain working on the site… so I apologize in advance for that!).

So, who does everyone use?  I’ve checked out Gate.com, Lunarpages.com, and discountasp.net, but can’t find one that meets what I’m looking for…

  • Shared server is OK
  • 1–5GB of web space
  • SQL Server 2005 support; multiple databases, 500MB+
  • AJAX 1.0, .NET 3.0 support (3.5 beta 1 would be awesome)
  • One FTP account, at least.
  • Ability to publish from VS2005/Orcas a plus, but not required… I can copy files with the best of them

I don’t need 25,000 email accounts, all the components under the sun (I provide my own), or support for any other languages besides .NET…

I’m open to any suggestions or even alternatives.  I post 99% of my “content” here on WordPress, but still need a spot for prototyping and a testing ground for sites I do for friends, family, and potential clients—without spending a paycheck to get it. *grin*

 [update: 6/15: 12:08pm – Lunarpages.com seems like a decent match after talking to them with one exception—they don’t support AJAX.  Gate.com, the more I read, has HORRID reviews regarding services and random downtimes.   Back to the drawing boards.]

 [update: 6/15: 2:37pm – *sigh* As much as WebHost4Life really irks me off, no one seems to have a solution to match the features they offer for the price, so it looks like back to them for another year and keep looking.]

Tags: , , ,