.Net ramblings
# Thursday, 24 June 2004
Http Status 400 trying to send large DIME attachments

Testing out my new DIME attachment code with WSE2, i ran into http errors with large uploads.  The error i got was a System.Net.WebException saying that it was a bad request, Http status 400, with an event in the application log under WSE:

HTTP/ASMX Message Receive Failure: Microsoft.Web.Services2.Dime.DimeFormatException: WSE352: The size of the record uuid:c0c3c949-5fb1-4171-88aa-06ce14499e44 exceed its limit.
at Microsoft.Web.Services2.Dime.DimeRecord.UpdateTotalBytesRead...

I had the maxRequestLength set to 128000 in web.config, but i found out that this does not apply to WSE2.  adding the following entry into web.config solved the problem.

<?xml version="1.0" encoding="utf-8" ?>
 <configuration>
  <microsoft.web.services2>
   <messaging>
    <maxRequestLength>256000</maxRequestLength><!-- 256 mb -->
   </messaging>
 </microsoft.web.services2>
...

Thursday, 24 June 2004 09:49:24 (GMT Daylight Time, UTC+01:00)  #    Comments [8]  Asp.Net

# Wednesday, 23 June 2004
WSE 2.0 send DIME attachments from client TO a web service

I wanted to improve the performance of my winforms app sending binary data to a web service, so i chose to upgrade to WSE 2.0 and use the DIME specification. 

I checked out the examples in the docs, but only found one with a web service sending an attachment to a client.  i wanted it the other way around.  i tried to modify it to suit my own needs, but couldn't get it to work. (in the end i had the response and request contexts mixed up). I searched high and low online and finally found that there is a sample as part of the WSE full installation which contains just what i wanted.  I could find no mention of this sample in the docs, so I am posting it here.

The code below shows the important methods, on the client and on the server.  It assumes a web project and winforms project both set up for WSE2.0. 


// this is part of a winforms application with an openfiledialog
private void btnUpload_Click(object sender, System.EventArgs e)
{
  if(this.openFileDialog1.ShowDialog() == DialogResult.OK)
  {
    DimeAttachment dimeAttach = new DimeAttachment("image/gif", TypeFormat.MediaType,this.openFileDialog1.FileName);
    ws = new TestService.Test();
    ws.RequestSoapContext.Attachments.Add(dimeAttach);
    ws.ReceiveImage(Path.GetFileName(this.openFileDialog1.FileName));
    MessageBox.Show("Upload successful");
  }
  else
    MessageBox.Show("No file selected");
}

// web service method...
[WebMethod]
public void ReceiveImage(string filename)
{
  // Reject any requests which are not valid SOAP requests
  if (RequestSoapContext.Current == null)
    throw new ApplicationException("Only SOAP requests are permitted.");
  if (RequestSoapContext.Current.Attachments.Count == 0)
    throw new ApplicationException("No attachments were sent with the message.");

  try
  {
    FileStream f = System.IO.File.OpenWrite(Server.MapPath("Upload/" + filename));
    Stream s = RequestSoapContext.Current.Attachments[0].Stream;
    byte[] bytes = new byte[s.Length];
    s.Read(bytes, 0, bytes.Length);
    s.Close();
    f.Write(bytes, 0, bytes.Length);
    f.Close();
  }
  catch(Exception ex)
  {
    throw ex; // or log it...
  }
}

Wednesday, 23 June 2004 13:08:19 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  .Net General

# Tuesday, 22 June 2004
Adventures with .NET smart clients, running with Local Intranet permissions

I had originally deployed an app with msi but the advantages of smart clients soon began to convince me to change my deployment model.

What you can and can't do in Local Intranet

As a smart client, the app is executed as http://myserver/exec/myApp.exe
This works very nicely, until those security exceptions start appearing.  I had to spend a long time going through my app to find out what was causing the exceptions.  The obvious reason for the exceptions is that programs coming in from the Intranet are less trusted than those on My Computer, and hence are subject to more restrictions by the local security policy.  After much exploration and reading up online, i found out some interesting facts:

  • you can't access Environment.Machinename
  • you can't access My Documents, or UserAppDataPath, etc.
  • you can't call abort() on a Thread, but you can call Sleep() and Start()
  • you can read files through openFileDialog
  • you can read and write to IsolatedStorage (a virtual file-system specially for your app), very useful seeing as you can't write to any physical location on the hard disk by default.
  • you can invoke delegates asynchronously

You could deduce these by looking in the .Net Framework Security Policy (control panel > admin tools > .Net Framework configuration > Runtime security policy > Machine > Permission Sets > Local Intranet), and then double click one of the items in the main pane to the right, to see what restrictions if any are applied for the selected zone.

I found out the above information hard way through trial and error, but it was a very valuable exercise to learn about the security policy.

Using a class library with your smart client app

I got a large part of my app working, but i was using a class library of customised windows forms components, and this was causing a security exception.  It took a few hours to pin down, but the docs finally revealed that the class library must have the following attribute (outside a class declaration):

[assembly:AllowPartiallyTrustedCallers] 

The app worked fine after I added that line.

Requesting permissions from the local Security Policy before your app runs. 

If you are not sure what zone your app will run in, you can request a minimum level which your app requires. Add the following line of code outside a class declaration in one of the files in your project:

[assembly:PermissionSetAttribute(SecurityAction.RequestMinimum, Name = "LocalIntranet")]

This will alert the user that they don't have permissions to run the app if it is running in a zone less than Local Intranet. 

Conclusion

I personally have found these bits of information very difficult to pull together.  There is a ton of stuff about smart clients but its mostly non-technical.  I even got a CD from msdn about smart clients and i found it useless for helping out with any of the problems i have encountered along the way.

I hear there is a tool called PermCalc.exe coming with Whidbey that will probe an app to see what would cause security problems in a smart client scenario but until then, we are stuck doing it manually :)


Tuesday, 22 June 2004 19:16:34 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  .Net Windows Forms

# Monday, 31 May 2004
Installing Windows XP on a Shuttle ST61G4 with SATA hard disk (no floppy drive)

This is my first post on my new PC, a Shuttle ST61G4.  3Ghz P4, 1Gb ddr 400 ram, 160Gb SATA hard disk.  It feels like a small miracle that it's working, that's how difficult it was for me to install Windows XP on the SATA hard disk.  

Partly it was due to me never having used SATA before, and not realising that Windows XP doesn't bundle the SATA drivers I need for the Silican SATA Controller (Si3112r) that is part of the Shuttle mainboard.  Also, the most annoying part was that Windows setup only allows you to specify additional drivers from a floppy disk.  The shuttle, being a modern compact PC, doesn't come with a floppy of course, so i was stumped.  I really didn't want to pull out the old floppy drive from my other PC, but i was forced to in the end. 

There is a way to slipstream the drivers into the Windows setup files and then burn them back to a CD, but this sounded way too complicated for me. 

The CD with the shuttle mainboard drivers had instructions for how to create the required floppy for a Windows install, and this worked OK, when i finally figured out how to get the Shuttle to recognise the floppy drive.  It took a while to find the plug in the motherboard for the floppy, at the back around the side under the power supply.  Then i had to enable Floppy Disk 1 in the bios as a 1.44mb drive.  Still didn't work, so i enabled Boot up Floppy Seek.  Still didn't work, and i finally found out that another setting 'FDC Controller' was disabled, which i needed to enable.  Then the floppy drive worked, and it went without hitch from there on in.  you also need to enable the Raid controller in the bios. 

When the computer boots, the SATA controller part still says "Drive 1542311Mb - Drive not found" or something, although this doesn't seem to matter since windows is able to recognise it. 

I found all this out the hard way, and i looked for a long time online to find an easier way of doing it, or clear instructions detailing every step necessary, and i found a FAQ page on shuttle.com (afterwards!) which details the process very well, its a shame it was so hard to find through the shuttle web site. 

But my shuttle is fast and very lovely, and it is the quietest thing i have never heard. I can't figure out why they make you press the reset button with a pen though, its so tiny.  In the end, i love it.  


Monday, 31 May 2004 00:20:44 (GMT Daylight Time, UTC+01:00)  #    Comments [2]  General

# Monday, 24 May 2004
Environment.SpecialFolder enumeration not showing up in Visual Studio Intellisense

I was using an OpenFileDialog and i wanted it to open at the My Pictures folder for the current user.  So i looked up the msdn docs for how to locate this folder, and i come across the Environment.SpecialFolder enumeration, which has an entry for MyPictures.  Great, my code then was:

this.openFileDialog1.InitialDirectory = Environment.SpecialFolder.MyPictures; 

but this didn't compile, and it didn't show up in Intellisense.  I read a few examples online which used the following syntax:

this.openFileDialog1.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures); 

and it worked, although it still didn't show up in Intellisense.  you'd think MS would at least explain this in the docs, weird.


Monday, 24 May 2004 12:34:15 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  .Net Windows Forms

# Saturday, 17 April 2004
Use a HOSTS file to block banner ads

You can use the HOSTS file in Windows to prevent banners from displaying in web pages.  It is usually in c:\windows\system32\drivers\etc. Note that it has no file extension. There are a few good sample files online that contain thousands of known advertisers.  I use http://everythingisnt.com/Hosts as a reference.  If that link is down, use my mirror copy (29 k).  The way it works is by redirecting the url (e.g. ad.doubleclick.net) to your own computer, instead of the proper doubleclick.net server.  Your local web server (if you have one) won't contain any of banner images or pages requested and you see a 404 page not found in the browser in place of the banner image / web page.


Saturday, 17 April 2004 17:53:23 (GMT Daylight Time, UTC+01:00)  #    Comments [1]  General

# Saturday, 03 April 2004
ADO.NET parameter quirks with ODBC and OleDb

The OleDb Provider

If anyone is using the Oledb provider with .Net, when you are adding parameters to an OleDbCommand in code, make sure you add them in the order that they belong in the sql string. 

For example, if your sql string is:
"insert into table1 (username, password) values(?,?)"
and you have parameters added to the command (usually done through a configure OleDbDataAdapter wizard), called "@Username" and "@Password".  Your code must add the parameters in the correct order as follows:
this.oledbCommand1.Parameters("@Username").Value = username;
this.oledbCommand1.Parameters("@Password").Value = password;

If you don't do it this way, you may get a jet error: "No value given for one or more required parameters.". 

This quirk does not apply for the Sql provider in ADO.NET, because you can name the parameters in the sql string, e.g. 
"insert into table1 (username, password) values(@Username, @Password)"

The ODBC Provider

If you're using the ODBC provider with .NET (probably for MySQL), there is one oddity that you should know about too.  In sql strings for odbcCommand objects, you can't use the @ParamName syntax.  You have to use question marks as placeholders for the parameters as follows:
"insert into table1 (username, password) values(?,?)"
Similarly, you have to add the parameters in the right order. 


Saturday, 03 April 2004 18:07:08 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  Database

# Thursday, 01 April 2004
Working around DVD install problems. Use Xcopy instead...

when i was building my computer, i got a cheap DVD drive, and i'm paying for it now with trouble installing any of the software that came on DVDs with my MSDN subscription.  I tried installing Windows Server 2003 from the DVD by booting straight from the CD but it failed at different stages, saying file not found, or corrupted files etc.  I'm convinced its because of the quality of the dvd drive.  To be safe, I now copy all the files to the hard drive and then install from there.  Even copying the files to the harddisk through Windows was not trivial as ms point out in http://support.microsoft.com/default.aspx?scid=kb;en-us;Q318945, they recommend using the xcopy command to verify that the files are copied correctly. The copy speed with xcopy was several times faster than using windows explorer, I have no idea why, but i always do it that way now. The syntax is:

xcopy <source> <destination> /V /H /Y /E

e.g. (from the command prompt. Start > Run > cmd.exe)
xcopy E:\VS2003\ C:\Local\VS2003 /V /H /Y /E

The switches mean:
/V = verify
/H = hidden files
/E = sub folder including empty folders
/Y = suppresses prompting to overwrite


Thursday, 01 April 2004 15:25:50 (GMT Daylight Time, UTC+01:00)  #    Comments [0]  General

# Friday, 26 March 2004
Micorosft Empower Program, the motivation behind it...

My application to join the MS Empower Program for ISVs was accepted this week.  The first thing I did was go straight to the MSDN download section and drool over all the software now available to me to download.  (Shame I'm on 56k... oh eircom get your act together and deliver broadband soon, it's not like I live in the sticks or anything <moan moan>)

For a €375 subscription fee I get the equivalent of €30k worth of software, of which I will realisitically only use a few thousands worth, but still, how bad.  There are a few costs associated with it, like a software verification test, digital ID from Verisign etc. but it's still a great deal, and actually the cheapest way for me to start using Visual Studio 2003 architect. 

I sat today wondering why MS are acting so desperate to get ISVs like me to write software for .Net in particular.  Then it struck me... (a rare moment of mental clarity), and I remembered back to what a man was saying at a Longhorn conference I was at earlier in the year.  He said that Windows Longhorn will run with 2 kernels, one for Win32 apps and a new kernel for apps written in .Net, i.e. managed code.  This is obviously great for backwards compatibility, with the advantages being given to new applications with the new kernel.  BUT... what if .Net apps don't become mainstream for 5 or more years?!  the new kernel will be more or less unused and we might as well be running a souped up XP pro instead.  Avalon, the new user interface, will also only work with .Net apps (.Net 2.0 at that), and other apps will look the same as XP.  It is no wonder MS are not giving a solid release date for Longhorn, since I reckon it depends on the take-up of .Net software.  If it is great, they will push to release longhorn early to give users the advantages of running .Net apps on a managed operating system.  But if it is slow, they will throw more and more resources to the developers and software companies in programs like Empower for ISVs until the knock-on effect of that is to put a whole lot more .Net software in to the marketplace until .Net becomes the standard. 

Here we are 2 or 3 years into the launch of .Net and most people around here still think it's bleeding edge technology if they have heard of it all.  (Yes there is a modern side to Ireland, but a lot of it is still running Windows 95, that's the reality of the environment we are building software for).

Something about knowing that my apps will one day execute in a managed Kernel in Longhorn really gets me going :) but i think it might be longer than MS think before it becomes the norm.


Friday, 26 March 2004 23:57:16 (GMT Standard Time, UTC+00:00)  #    Comments [3]  General

# Tuesday, 16 March 2004
Howto: use MySql with .Net

MySQL is a great alternative to SQL Server because it is open source and nearly has the performance to rival SQL Server. Applications using Microsoft Access databases can suffer seriously if the transaction load is anything above minimal. This article is my collection of instructions and tips for getting up and running with MySQL and .NET.

Downloads

  1. Download & Install MySQL 4.0 (16 Mb)

  2. Download & Install ODBC.NET Data Provider (800 k)

  3. Download & Install MyODBC 2.5 (1.5 Mb)
    Note: the newer versions do not work with .NET at time of writing

  4. Optional: Download & Install DBManager, GUI for MySQL tables, highly recommended (3 Mb)

Testing

  • Make sure the MySQL service is running in Windows.

  • Load up the WinMySQLAdmin.exe tool in the bin folder of your MySQL install. This program controls the MySQL server. Feel free to customise any settings you wish, e.g. change the Server Name, Port Number, username & password etc.

  • Load up DBManager and connect to the Server. The default user is root with a blank password. You can create your own users or keep using the root. Create a test database and then right-click the 'Tables' node under the database you just created. Use the 'Table Editor' to define the fields for the table. Click the 'Save' icon to save your changes. Users from MS Access backgrounds may want to read below.

To connect to the database through .NET code:
Add a reference to Microsoft.Data.Odbc.dll, this should be in 'C:\Program Files\Microsoft.NET\Odbc.Net'

using Microsoft.Data.Odbc;
...
stringconnString="'driver={MySql};uid=root;pwd=;server=127.0.0.1;database=test;OPTION=17923";
string sql = "select * from table1 where ShortName = ?";

// declare an OdbcCommand object with a new OdbcConnection
OdbcCommand command = new OdbcCommand(sql, new OdbcConnection(connString));
// add a paramter to the command corresponding to the ? in the sql statement
OdbcParameter dbParam = new OdbcParameter('ShortName", OdbcType.VarChar, 50);
dbParam.Value = "bob";
command.Parameters.Add(dbParam);

DataSet ds = new DataSet();
OdbcDataAdapter dba = new OdbcDataAdapter();
dba.SelectCommand = command;
try
{
  command.Connection.Open();
  dba.Fill(ds);
}
catch(Exception ex)
{
  throw ex;
}
finally
{
  command.Connection.Close();
}

Unfortunately, MS never provided OdbcDataAdapter & OdbcCommand GUI support for Visual Studio so you have to do all that manually, as in the code above. However, there are commercial components that solve this.

The 'System Error' ODBC message
If you get a 'System Error' message thrown in your code using MySQL, with no useful information, you need to catch the line of code causing the error and throw the exception explicitly (i have no idea why, but MS have a kb article about it).

Note on DBManager Queries
This version of MySQL doesn't support Stored Procedures, but you can still save queries to the database. Click the 'Create new query' button in DBManager and enter the SQL you want. There is a query designer but the intellisense doesn't work well and it can be annoying to use. Save the query and it appears as an extra tab after 'DataSheet' in the lower right corner. When you close DBManager, next time you open it, that tab won't be there and it will look like the query was only temporary. They are actually stored permanently, and accessible via the 'Tools' tab on the lower right of the screen.

Notes on the MySQL field types for anyone from an MS Access background

  • MySQL uses the single apostrophe character for quoting values, e.g. select * from table where name = 'bob'. the double quote character causes a syntax error.
  • there is no 'bool' field type as such, use 'TinyInt' and change the size to 1 bit, then use 1 to represent true and 0 for false.
  • the varchar field type is limited to 255 characters, in MS Access you would use a Memo to go beyond this. MySQL has the tinytext, mediumtext and longtext field types to support larger max characters.
  • to force the input to match a list of values, e.g. Categories: Animal / Vegetable / Mineral, use the 'Set' field type, with comma separated values in single quotes: 'Animal', 'Vegetable', 'Mineral'
  • the 'Now()' function is supported in MySQL as a default value for a DateTime or Date field, but when you enter this in DBManager, the value appears as 0000-00-00 00:00:00 in the Table Editor, this seems unusual but the function works as expected.

BTW, if you're looking for .NET web hosts that support MySQL, check out www.webhost.ie


Tuesday, 16 March 2004 23:27:39 (GMT Standard Time, UTC+00:00)  #    Comments [0]  Database