Green Light live webdesign

.NET C# ASP.NET

August 23, 2010 - C# GUID's (Global Unique Identifier)


GUID's are special identifiers used to uniquely identify an item in a database. GUID's are usually stored as 128-bit integers (16 bytes). Using GUID's removes the possibility of say having a userid and product id match, for example:

USER
id=1
name="joe blogs"

PRODUCT
id=1
product_name="GUID's for dummies"

With a GUID as the unique identifier we would have:

USERPRODUCT
id=2613f325-08c1-43ae-9acf-5b27f03be280
name="joe blogs"

PRODUCT
id=5cc6f24c-6d77-4ef7-ba84-659b0430e81c
product_name="GUID's for dummies"

GUID's specifically refer to Microsoft's implementation of the Universally Unique Identifier (UUID) standard. The primary purpose of a GUID is to have a totally unique id that will never be generated twice by any computer or group of computers in existence. There are 2128 or 3.4x1038 unique possibilities and the possibility of the same number being generated more than once is extremely small.

To generate a GUID in C#, Microsoft has included the GUID namespace as part of the System namespace:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
   protected void Page_Load(object sender, EventArgs e)
   {
      Guid myguid = new Guid();
      myguid = Guid.NewGuid();
      Response.Write(myguid);
   }
}

That's all there is to it, now you have a unique GUID every time the page loads.

July 12, 2010 - C# Convert a Nullable Variable to a non-Nullable Variable


For many of our objects we are using default properties of NULL, however many methods are expecting no nullable parameters. To overcome this we need to constantly be converting nullable properties to non-nullable properties, something that can get very annoying after a while and something that I wanted to make sure we were doing as efficiently as possible, from a coding stand point.

The most widely used solution we found in our existing code was the TryParse method, this I always find cumbersome as you have to create a variable to pass in and remember to OUT keyword:

long lngssClientID = 0; if (long.TryParse(lngssClient.ToString(), out lngssClientID)) lngssClientID = long.Parse(lngssClient.ToString());

Another option, and one that looks somewhat cleaner and easier to write was to use a shorthanded IF and the HasValue method:

long longClientValue = lngssClient.HasValue ? lngssClient.Value : 0

The best solution we were able to come up with was to use the GetValueOrDefault method:

long? lngWhatever = 0; long lngWhatever2 = 0; lngWhatever2 = lngWhatever.GetValueOrDefault();

With GetValueOrDefault you can also override the default value returned (0) if there is no value by specifying the value you would like. This is especially useful as we are using -1 to represent a non selected value.

Now whenever we need to convert a nullable data type to a non-nullable type we use the GetValueOrDefault:

long lngMyParam = myObject.myProperty.GetValueOrDefault(-1);

This helps keep our code cleaner and easier to follow. Now to add this conversion to our base class to make things even tidier.

May 25th, 2010 - Disabling Server Side Button with jQuery And Determine which Control Caused the PostBack


Working on a page with a (potentially) long postback time, I had the need to disable the submit button onclick so that the users could not click on the submit button multiple times and cause multiple PostBacks -- resulting in multiple records being saved and increasing the time for the PostBack to return.

Possible solutions:

  1. Cause the PostBack, but only disable the button and force another PostBack to do the save, re-enable the button when the save is complete - very clumsy.
  2. Use jQuery (or plain old Javascript) to disable the submit button on the client side - easy and clean, somewhat...

 

It was easy enough to disable the submit button onclick:

$(document).ready(function() {     $("#<%=cmdSave.ClientID%>").click(         function() {             $(this).attr("disabled","disabled");         }); });

This worked a treat, however, now on PostBack the code behind did not know which control caused the PostBack, something that was need for the page in question.

The next step was to force the PostBack from the client side jQuery using the controls UniqueID to be rendered into my Javascript on page load and impersonate as causing the PostBack:

$(document).ready(function() {     $("#<%=cmdSave.ClientID%>").click(         function() {             $(this).attr("disabled","disabled");             // force PostBack, simulating the save button was clicked             __doPostBack('<%=cmdSave.UniqueID%>', ''); // this will render ct100$ContentPlaceHolder1$cmdSave         }); });

Now on the server side I could use FindControl to determine which button caused the postback:

string ctrlname = page.Request.Params["__EVENTTARGET"]; Control control = page.FindControl(ctrlname);

20 April, 2010 -- Bind an Enum Types to the Dropdown or other bindable Control in ASP.Net/C#


The great thing about bind-able controls in ASP.NET is that you can bind them to pretty much any data source fairly easily, its just knowing the right syntax that can stand between you and your binding bliss. Having just needed to refresh my memory on how to bind an Enum to a drop-down I thought I'd write a quick post. In a nutshell you just need to use the "GetNames" static method that is inherited from the System.Enum namespace.

Here is a quick example, first declare our Enum and values:

public enum DistributionType { AccountingEmail=1, SysAdminEmail }

We have two static methods that help us bind to a drop-down list control, Enum.GetNames and Enum.Parse, GetNames allows us to bind to our drop-down like so, assuming we have a drop-down control on our page named "ddDistributionType":

private void Page_Load(object sender, System.EventArgs e)
{
if(!IsPostBack)
{
ddDistributionType.DataSource = Enum.GetNames(typeof(DistributionType));
ddDistributionType.DataBind();
}
}

Finally, if we wanted to convert the selected value back to your Emum, we would do:

private void ddColor_SelectedIndexChanged(object sender, System.EventArgs e)
{
 DistributionType selectedDistributionType = (DistributionType)Enum.Parse(typeof(DistributionType), ddDistributionType.SelectedValue);
}

16 October, 2009 -- A Full list of ADO Connection Strings


Full article - ADO Connection Strings by Carlos Antollini on The Code Project.

I recently came across this great recourse of ADO Connection Strings on The Code Project put together by Carlos Antollini. He covers the majority of known databases giving the proper syntax for each covering DNS-Less, DNS connections OLE DB Providers and OLE DB Data Link Connections. Even though it’s an old post (2002) it’s still a good resource.

17 July, 2009 -- Complex DataBinding with Expression Conditionals in ASP.NET


I just came across the need to format a data bound textbox in a asp:GridView to use a comma as the thousands separator, however some rows needed to have 2 decimal places whilst some required no decimal places. One the client side as users enter the data I was able to (somewhat) easily accomplish this using jQuery and my own java script to test and update the text boxes on blur. However, when the page loads I was faced with the problem of populating fields some with decimal places and others without. This would be simple if they were all the same, I could simple specify the format string I want:

Bind("MYVALUE","{0:n2}")

However, how to determine which fields need to not have the decimal places? And how to accomplish this? My first thought was that I could simple format the data on the server side, but to do that I would have to modify several files; I wanted to keep this as simple as possible with the least number of changes. So, I decided to see how I could do this from the aspx page itself using Bind. After fiddling around with using shorthand IF's to test the Binding of the field that I needed to base my decimals/no decimals on I hit the web and found this post that pointed me in the right direction: http://www.pluralsight.com/community/blogs/fritz/archive/2005/12/16/17507.aspx over at pluralsight.com. Using Eval instead of Bind this is what I came up with:

<%# ((string)Eval("FIELDTOTEST")=="VALUETOCOMPARE") ? Eval("FIELDTODISPLAY") : Eval("FIELDTODISPLAY","{0:n2}") %>

2 June, 2009 -- Microsoft Dynamics GP 10 – Passing Credentials to Web Service


I spend some time on trying to figure out how to pass a service accounts credntals to my Dynamics GP so that I didn;t have to use the default crednential, those of the user executing the Web Service Methods -- this would cause to much of a headache to maintain and to just use one service level account would make adminstering the Web service a lot easier, especially as we add more developers to the project. Luckilly, DynamicsGP has a property Credentials just for this. For other Web Services we have been using System.Net.CredentialCache, and this worked just fine for those. However, nothing is quite as easy with DynamicsGP, or so it seems, and this did not work. After some experimenting and reseach I found that instead of System.Net.CredentialCache I needed to use System.Net.NetworkCredential, below are 2 methods for implementing this:

DynamicsGPService.DynamicsGP wsDynamicsGP = new DynamicsGPService.DynamicsGP();
System.Net.NetworkCredential iCredNetWk = new System.Net.NetworkCredential("YourUserName", "YourPassword", "YourDomain");
wsDynamicsGP.PreAuthenticate = true;
wsDynamicsGP.Credentials = iCredNetWk;

Or

DynamicsGPService.DynamicsGP wsDynamicsGP = new DynamicsGPService.DynamicsGP();
iCredNetWk.Domain = "YourDomain";
iCredNetWk.Password = "YourPassword";
iCredNetWk.UserName = "YourUserName";
wsDynamicsGP.PreAuthenticate = true;
wsDynamicsGP.Credentials = iCredNetWk;

Of course you then need to grant access to the DynamicsGP Web Service for the service account that you are going to use.

18 May, 2009 -- Microsoft Dynamics GP 10 – Sales Order Processing (SOP) – Retrieve Tracking Numbers Through Web Service


Just a quick follow up to my last post about saving data to the User Defined Tracking Number frields through the Microsoft Dynamics GP 10 Web Service, I figured I'd write a quick post on how to retrieve data from the Tracking Numbers fields. As I said in my previous post, we are using to Tracking Number field to hold the invoice id from one system so that we can map back to it down the road.

First we need to create a SalesTrackingNumber Array to hold the Tracking Numbers array that is returned with the Dynamics Document, we then need to loop through the array to find the record that we are interested in:

DynamicsGPService.CompanyKey companyKey;
DynamicsGPService.Context context;
DynamicsGPService.SalesDocumentKey salesInvoiceKey;
DynamicsGPService.SalesInvoice salesInvoice;

// Create an instance of the web service
DynamicsGPService.DynamicsGP wsDynamicsGP = new DynamicsGPService.DynamicsGP();

// Be sure the default credentials are used
wsDynamicsGP.UseDefaultCredentials = true;

// Create a context with which to call the web service
context = new DynamicsGPService.Context();

// Specify which company to use (sample company)
companyKey = new DynamicsGPService.CompanyKey();
companyKey.Id = (0);

// Set up the context object
context.OrganizationKey = (DynamicsGPService.OrganizationKey)companyKey;
context.CultureName = "en-US";

// Create a sales document key
salesInvoiceKey = new DynamicsGPService.SalesDocumentKey();
salesInvoiceKey.Id = "INV11111"; // GP Document Number to be retrived

// Retrieve the sales invoice
salesInvoice = wsDynamicsGP.GetSalesInvoiceByKey(salesInvoiceKey, context);
DynamicsGPService.SalesTrackingNumber[] arrSalesTrackingNumber = salesInvoice.TrackingNumbers;
foreach (DynamicsGPService.SalesTrackingNumber tn in arrSalesTrackingNumber)
{
   // Loop through the TrackingNumber array and find the entires you need, or populate you own object
}

16 April, 2009 -- Microsoft Dynamics GP 10 – Sales Order Processing (SOP) Web Service Tracking Numbers


I am currently working on an integration project with Microsoft Dynamics GP 10 using the new Web Service that it exposes. As part of this integration we need to pass an invoice id from one system into Dynamics for future reference and retrieval. After looking at all the available fields and user defined fields, the only reliable field that we could use is the Dynamics Tracking Number fields as all the others are being used. Well looking at the Web Service and the CreateSalesInvoice method, it seemed like it would be pretty simple and straight forward to populate the TrackingNumber property and create the invoice. Well, since I am writing about it, it was not as straight forward as we first thought, and I did not find much help online for this, the best I could find was the Microsoft online help here which to say the least is very lacking.

Many of the SalesInvoice properties are themselves objects and array objects, such as the DocumentTypeKey, OrganizationKey and SalesInvoiceLine to name a few. The TrackingNumber is no different, only I could find no help on how or what objects to use. Searching through the online help I was able to ascertain that the TrackingNumber property needs to be populated with an array of tracking numbers and that the array of tracking numbers is made up of SalesTrackingNumber and SalesTrackingNumberKey. To get this far I needed to write some test code that pulled an invoice out of Dynamics to that I could step through the object, what I found was:

myObject.TrackingNumbers
     [0]{DynamicsGPService.SalesTrackingNumber}
          Key: DynamicsGPService.SalesTrackingNumberKey
               id: “the tracking number”
               SalesDocumentKey: {DynamicsGPService.SalesDocumentKey}
                    id: “the GP Invoice Id”
          Extension: {DynamicsGPService.Extension[0]}

Armed with all that I still had a hard time taking my SalesTrackingNumber and assigning it to my objects TrackingNumbers. It turns out that you need to create a separate SalesTrackingNumber[] array to add the SalesTrackingNumber to and then add the array to myobject.TrackingNumbers like so:

DynamicsGPService.SalesInvoice salesInvoice;
DynamicsGPService.CompanyKey companyKey;
DynamicsGPService.Context context;
DynamicsGPService.SalesDocumentTypeKey salesInvoiceType;
DynamicsGPService.CustomerKey customerKey;
DynamicsGPService.BatchKey batchKey;


// Create an instance of the web service
DynamicsGPService.DynamicsGP wsDynamicsGP = new DynamicsGPService.DynamicsGP();

// Be sure the default credentials are used
wsDynamicsGP.UseDefaultCredentials = true;

// Create a context with which to call the web service
context = new DynamicsGPService.Context();

// Specify which company to use (sample company)
companyKey = new DynamicsGPService.CompanyKey();
companyKey.Id = (Id of your company);

// Set up the context object
context.OrganizationKey = (DynamicsGPService.OrganizationKey)companyKey;
context.CultureName = "en-US";

// Create a sales invoice object
salesInvoice = new DynamicsGPService.SalesInvoice();

// Create a sales document type key for the sales invoice
salesInvoiceType = new DynamicsGPService.SalesDocumentTypeKey();
salesInvoiceType.Type = DynamicsGPService.SalesDocumentType.Invoice;

// Populate the document type key for the sales invoice
salesInvoice.DocumentTypeKey = salesInvoiceType;

// Create a customer key
customerKey = new DynamicsGPService.CustomerKey();
customerKey.Id = "Id of your customer";

// Set the customer key property of the sales invoice
salesInvoice.CustomerKey = customerKey;

// Create a batch key
batchKey = new DynamicsGPService.BatchKey();
batchKey.Id = "Your batch Id";

// Set the batch key property of the sales invoice object
salesInvoice.BatchKey = batchKey;

// Sales invoice total amount
DynamicsGPService.MoneyAmount invoiceAmt = new DynamicsGPService.MoneyAmount();
invoiceAmt.Currency = "USD";
invoiceAmt.DecimalDigits = 2;
invoiceAmt.Value = (decimal)1000;

salesInvoice.InvoiceDate = DateTime.Parse("4/16/2009");

//Add our invoice id to the GP Tacking_Number field

// this is the object that we are going to add our invoice number to
DynamicsGPService.SalesTrackingNumberKey salesTrackingNumberKey = new DynamicsGPService.SalesTrackingNumberKey();
salesTrackingNumberKey.Id = "You TrackingNumber";

// this is the object that we need to add our invoice number to as a Sales TrackingNumberKey and Add this to salesInovice.TrackingNumbers
DynamicsGPService.SalesTrackingNumber salesTrackingNumber = new DynamicsGPService.SalesTrackingNumber();
salesTrackingNumber.DeleteOnUpdate = false;
salesTrackingNumber.Key = salesTrackingNumberKey;

// Now create a SalesTrackingNumber array to add out salesTackingNumber to, if we have multiples we can add here
DynamicsGPService.SalesTrackingNumber[] SalesTrackingNumberArray = { salesTrackingNumber };

// Finally add the SalesTrackingNumber array to the salesInvoice TrackingNumbers.
salesInvoice.TrackingNumbers = SalesTrackingNumberArray;



// Get the create policy for the sales invoice object
salesInvoiceCreatePolicy = wsDynamicsGP.GetPolicyByOperation("CreateSalesInvoice", context);

// Create the sales invoice
wsDynamicsGP.CreateSalesInvoice(salesInvoice, context, salesInvoiceCreatePolicy);

13 February, 2009 -- Clear the Recent Project List from Visual Studio 2008


I've often wondered how I could clear the Recent Projects list on the startup screen of Visual Studio, both 2005 and 2008. I often end up with sample project littering the list and today I had several with the same names from doing some trouble shooting yesterday. The problem here is which one is the one that I really want to work with. I know hovering over the solution name I can see the path in the status bar, but I just know, at some point with multiple solutions with the same name I'd open the wrong one and not realise right away. So I set out to find a way to clear the Recent Project List.

Right clicking did nothing, I was hoping for a context menu to popup. I then searched the menus, and was hopeful that I would find something under Tools – Options, but not there. After doing a quick search on the internet I found the solution, edit the registry. Nice! I did find some tools that can be downloaded and added to Visual Studio as external tools, or scripts that can be run, but I tend to be weary and decided to go with editing the Registry.

For Visual Studio 2008 navigate to, and delete the entries that you want removed:

HKEY_CURRENT_USERSoftwareMicrosoftVisualStudio9.0ProjectMRUList

For Visual Studio 2005

HKEY_CURRENT_USERSoftwareMicrosoftVisualStudio8.0ProjectMRUList

The changes will be seen the next time you start Visual Studio.

If you break the file sequencing you will need to rename them so that they are in sequence again, otherwise the Recent Project list will only show the projects that are in succession. For example if you have 3 files:

File1
File2
File3

And you delete File2, when you restart Visual Studio, only File1 will appear in the list. Renaming File3 to File2 will then display your two projects in the list.

11 February, 2009 -- Access Master Page TreeView Control and Expand a Node


I wanted to write this down someplace so I wouldn't forget it when the need arises to use it again. If you have a ASP.NET TreeView control in your master page, you can access it from any code behind (that is using the MasterPage) by creating an object reference to it as follows and then control its properties.

TreeView mptvNode = (TreeView)Master.FindControl("tvNavigation"); // create an object reference mptvNode.FindNode("[node value to expand]").Expand(); // Expand a node mptvNode.FindNode("[parent node]/[node to select]").Select(); // Select a node

In the example above I have my path separator set to '/' but you can set to whatever you like using the TreeView’s PathSeparator.

21 January, 2009 -- Access Server Side ASP.NET Controls SelectedValue when Populated Client Side / AJAX and jQuery


I recent was building a dynamic selector for a project utilizing 3 DropDownLists, for locations, clients and accounts. The selectors are to be utilized on several pages on the site and retain there selected options. The basic requirement is to have the location and client ASP DropDownLists populated server side using C#. Selecting a service location options would cause an AJAX call using jQuery to update the client list with only those clients serviced by the selected location. Finally selecting a client would then populate the accounts DropDownList with the client’s accounts, again using AJAX and jQuery. A save button would then enable the user to confirm the selection and on Post Back would grab the selected options and save them to the session. When the page is redrawn, either do to other actions on the same page or going to another page, the selected location, client and account need to be pre-selected and only the client and fund options for the selected location and client need to be populated in the DropDownList options.

By using the Save buttons Post Back method this was very easy to implement, and only when the save button is clicked will the saved options be updated in the session variables. This worked great for the Location, the same values would always be loaded and only the selected option would change. Pre-loading the clients available for the selected location and selected the client from the session variable was also no problem. However... for some reason the Post Back was not recognizing the selected account.

ddAccount.SelectedValue.ToString()

Was always returning an empty string, even though a value was being selected on the client side prior to clicking save. On the second attempt the value was being successfully captured and saved to the session variable. After several attempts this was always the case. I decided to try pre-populating the Account DropDownList with all the Accounts on Page Load and then select a client and using AJAX update the list. Clicking save the first time worked like a charm, however, changing Clint and selecting another account reverted to the same behavior, not recognizing the selected value and always being an empty string.

After some searching, I found the issue, since my Account DropDownList was being populated client side, the server side had no record of the options (in the case of pre populating with all Account options this was not the case and so it worked) and so returned an empty string, along with SelectedIndex of -1. So, server side you do not have access to the DropDownLists (or other ASP.NET Controls) that are only populated Client Side. To get around this, you need to use the Request object and reference the ddAccount server control with its client side unique id:

Request[ddAccount.UniqueID].ToString()

Now, using this you can now access an ASP.NET Server Side Controls value when populating strictly from the Client Side using AJAX or JavaScript. There are other ways to work around this "limitation". The simplest, and in my opinion hokiest, is to use a hidden field ASP.NET Control, and populate Client Side whenever a new option is selected. There is nothing really wrong with this, and I have used it in the past and was considering it, but wanted to find a cleaner option. Other options would be to use an UpdatePanel and/or ASP.NET AJAX controls. But for this and many of my other projects I am using jQuery as it is a much lighter load.

10 December, 2008 -- Installing ISS on Windows XP - Server Application Unavailable


I recently had to install IIS to my XP laptop for testing ASP.NET applications and installing SQL Server 2005 Developer Edition with Reporting Services. Once setup I configured the Default web site (IIS on XP only allows for one website to be configured) to point to an existing .NET 3.5 website that I am currently working on for a Billing project. Once IIS was configured I fired up FireFox and went to my localhost I got the following error:

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.

I had to re-install the .NET 2 Framework by doing the following in order to fix the issue.

  1. Open a command prompt
  2. Stop IIS: iisreset /stop
  3. Change to the .NET Framework 2.0 root directory: C:\%systemroot%Microsoft.NetFrameworkv2.0.50727
  4. Reinstall ASP.NET 2.0 by using the following command: aspnet_regiis -i command.
  5. Start IIS again: iisreset /start

I am guessing that since .NET 2 (3 & 3.5) had already been installed prior to IIS the reinstalling of the Frameworks enabled the integration with IIS.

18 September, 2008 -- Consuming a Web Service from a Windows Consol Application


I recently had the need to write a console application that will poll a database for a list of reports that need to be generated by SQLServer Reporting Services (SSRS) and trigger the reports synchronously so that we did not bring the servers being used to generate the reports to there knees.

The consol app needed to interact with a Web Service for triggering the reports in SSRS. I was hoping that this would be as easy as adding the web reference to my project in Visual Studio 2005; I tried this and was unable to get it to work, admittedly, I only spend an hour or so on trying this method.

What I ended up doing was creating a Web Service proxy to the Web Service using the Web Services Description Language Tool (wsdl.exe) and then compiling its output into a DLL that I referenced in my project. In order to do so I need to run wsdl passing it the URL of the Web Service to be consumed:

wsdl http://[path-to-web-service]/service.asmx?wsdl

This generates the code for the proxy. (if the wsdl.exe tool is not in your system path, you will need to run it from the directory that it resides in C:Program FilesMicrosoft Visual Studio 8VC or just fire up the Visual Studio 2005 Command Prompt ).

Once the code was generated, it needed to be compiled, from the same folder that the code file resides in by running this command:

csc /t:library [your-files-name].cs

The resulting DLL was then copied to my project folder and added as a reference by right clicking on the projects name in the Solution Explorer (Visual Studio 2005) – Add Reference – then on the Browse tab locate the DLL.

Finally to consume the Web Service in the console app I simply instantiate it and called the method(s) that were need.

[dll reference name] rs = new [dll reference name](); rs.getReport();

16 September, 2008 -- ADO.NET OleDbConnection And Excel Datasource not reading all cell values


I recently build an import/export utility for one of out task tracking applications. The requirement was to allow a manager to export all there tasks to Excel for bulk editing, make changes and them import back into the application. Since they like using Excel I figured I’d export the data directly to an XLS file and import an XLS file and not bother them with CSV.

For the import side I use ADO.NET OleDbConnection to open the Excel Spreadsheet as a data source and to treat it like any other database table. This was easy enough to do with the following connection and then I was able to look through each row, do any data manipulations/validations on each cell and then import back in to the database. The only issue with this was that for no apparent reason, some of the cells, primarily date field would fail to be read in. I spend several days on trying to figure this out and I found a work around to convert everything to a text formatted field and to force dates to text by appending a single quote to the beginning of the value:

‘7/31/2008

This obviously was not an acceptable solution since I want the managers to be able to work with their data in Excel and not worry about formatting each cell. After much research, the issue definitely stems from the cells values not matching the data type that the OleDbConnection was expecting. The way that Excel works is that it reads the first 8 rows of a sheet to determine what the data type for the column should be, if multiple data types are encountered it goes with the mode (or most common) and then nulls out the ones that do not fit with the determined data type. This of course is not a good method as it can not accurately determine what the date type should be based on only 8 rows, and loosing any data that does not fit is not acceptable – and this is of course what was happening with my importers. The work around was to convert everything to text manually. Luckily there is a way to override this default behavior, however it is not 100% reliable, and that is to add IMEX=1 to the connection string like:

SqlConnection strConn = "Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + [path to file] + "; Extended Properties='Excel 8.0;IMEX=1;'";

Note: It is important to add the quotes (single or escaped doubles) around the Extended Properties.

That tells ADO.NET to honour the following registry key when reading the spreadsheet:

Hkey_Local_Machine/Software/Microsoft/Jet/4.0/Engines/Excel/ImportMixedTypes

This registry key tells ADO.NET what to do when it encounters mixed types in the first 8 rows. It can either be set to the string "Majority Type" (for the default behavior) or to "Text" (which forces the column to be of type string – string over 255 characters will fail). You are out of luck if the first 8 are not a true representation of all the cells in the column. This was able to fix my issue, and I know that all my columns will work for my import being text as I handle paring to different data types in code.

Lab49 has a great article that goes into more detail of reading Excel spreadsheets using ADO.NET.

5 September 2008 - C# Retrieve Text and other Properties from Object sender on Postback


I came across the need to have several ASP LinkButtons call the same code behind function, and I knew I could access which button was being used but racked my head for a while to remember, so I figured I should make note of it.

Here is the situation that I have (and I may go back and clean it up further and break things out before I am done with this).

On my ASP Form I have 2 buttons, one that is to grab all the selected options for running reports and save them for future use (“Save Report Settings”) the other to run the report (“Run Report List”) using SQL Reporting Services. The only difference between the 2 is that when running the reports I also have to make sure that a start date is entered and valid and the output type is selected, and of course fire the reports.

protected void linkSaveUpdate_Click(object sender, EventArgs e)
{
………
}

In order to retrive the text of the clicked Link Button you need to cast sender as the control:

((LinkButton)sender).Text

This will also work for any other ASP control that can perform a postback.

7 August 2008 - C# File.Copy() and Access Denied Resolved


Well I managed to solve the File.Copy() issue I had on the 5th. What was confusing about this issue was that it would fail only some of the time after implementing the steps that I detailed in my August 5th post. The 5th also happened to be the Western Mass .NET User Group meeting that I often attend and I took the opportunity to ask a few fellow .NET programmers if they have had the same issue. I few had and suggested reading the source file into memory as soon as I can on the page and then when I need to write it to disk I can do it from memory which would be much quicker. Armed with this I set about reading the source file into a bit array and this seemed to work, for the first 3 attempts and then after that it would still fail most of the time with the same access denied error when trying to write the file to disk. Since it was working some of the time, how could it be an access issue? I ensured that it could not be a conflict of file names, I was already creating a unique file name based on the current system timestamp, I event went so far as deleting everything from the destination folder.

After much frustration I through caution to the wind and went back to the destinations folder security settings and granted write access to the local systems Users group. And it worked, consistently. How can this be?? I do not have an explanation at this time but I will see what else I can unfold from this. My biggest question is why with the original security settings as laid out in my previous post would it would some times; surely it should have been failing all the time??

So, not wanting to leave the security the way it now was, I removed the write privileges from the local Users group and changed the user that the web app was running as, using the Impersonate abilities of .NET. This was simply a matter of adding the following to the system.web section of web.config file:

<identity impersonate="true" userName="[domain][username" password="[password]" />

Where the user has elevated privileges on the server. I went with a domain service account that has a password that is set to never expire, the last thing I want is to have it break in 6 months and find out its due to a changed password.

5 August 2008 - C# File.Copy() and Access Denied


I came across an interesting issue today with one of my apps. The app in question is a task tracker that is used to keeping track of repeated tasks that need to be performed daily, weekly, monthly, quarterly or annually by our staff. A recent requirement was to have the ability to export a bunch of tasks to Excel, modify them and reload them back in to the system, as well as have the ability to load new tasks in from Excel as well. For the export to Excel piece, I created a template workbook with the column headings that I wanted and then copy this to the download folder where I add the required tasks to the file treating the workbook like a database, connecting to it using the Microsoft.Jet.OLEDB.4.0 data provider. The issue that I ran into was when I pushed the app to our staging environment to be tested by the business owner; he was unable to export the file. The error that he was getting (in fact two errors) were:

Access to the path 'C:[path][file name].xls' is denied.

AND

Unable to export: No error message available, result code: E_FAIL(0x80004005).

The second error is not such an issue as it is being caused by the first step failing and the file not being there to write to, so that was easy to remedy, make sure the first step is successful first. The first error was perplexing though. Why was the copy (File.Copy()) failing for this user? I did some testing with others and for some it worked and others it did not, so I was hesitant to jump on the “Permissions” wagon. But what else could it be??? After doing some Googling, I gave one of my tester’s elevated privileges on the server and sure enough, that worked, they were able to generate the Excel export file. Now, since I was going to be rolling this out to about 30 or so managers, I did not want to give them all elevated privileges. I removed the privileges of my co-worker and set about finding out what the true issue was and how to resolve it. After lots of experimenting with privileges I ended up not only giving the IIS_WPG and Internet Guest Account users write access to the download folder at the file system level, but also added the local ASP.NET user with write privileges. Now things started to work, sporadically for my testers who before were only getting the error. So I started to wonder, could there be a timing issue, why that would cause the Access denied error I am unsure, but I put in a Thread.Sleep(500); just after the File.Copy() and I now the about 90% success rate. Even if I up the Sleep period to 1 second or higher, they still encounter the Access Denied error about 10% of the time, for myself, I have 100% success no matter what (but then I am an admin on that server), go figure. There has to be something else that is causing the problem, but with the Thread.Sleep(500) I have gone from about 20% success to 90%. If I remove any of the privileges I added to IIS_WPG and Internet Guest Account or ASP.NET users it falls back failing ever time for my testers.

4 August 2008 - Visual Studio 2005 Web Project Build ASP.NET Runtime Error System.EnterpriseServices


When setting up a new developer today and getting him started on one of our projects he was getting the following error when trying to compile the web project

 

Error 2 C:Devfsiswebmanagedefault.aspx: ASP.NET runtime error: Could not load file or assembly 'System.EnterpriseServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. C:Devfsiswebmanagedefault.aspx 1 1 C:Devfsisweb

I’ll admit this stumped me for a while. No one else on the team was having the issue and getting latest from VSS the project build for everyone without any errors.

A quick Googling found the solution, the .NET 2 System.EnterpriseServices.dll needed to be added to his GAC and this was simply a matter of copying from the install location.

 

“[windows_directory]Microsoft.NETFrameworkv2.0[subversion]System.EnterpriseServices.dll"

to the

“[windows_directory]assembly” folder.

 

30 July 2008 - C# Calculate Previous Quarters End Date


One of my current projects is a custom web front end to SRS (SQL Server Reporting Services) that needed to have the default dates set to the previous day, first of the month, last of the previous month and last day or previous quarter. Anything to do with the current ore previous month was not a problem, however, I was not so sure how I’d go about getting the last way of the previous quarter.

To get the first day of the current month, that was simply a matter of creating a new DateTime object based on the current year and month:

 

DateTime firstofmonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);

Then to get the last day of the previous month, all you need to do is a AddDay of -1 to the first of the month. The build in DateTime object handles figuring out if there are 28, 29, 30 or 31 days in the previous month for you, and handles the year if for January.

 

DateTime lastofpreviousmonth = firstofmonth.AddDay(-1);

Getting the last day of the previous quarter was a little more tricky. I ended up first figureing out the first day of the current quarter, and then applying the same idea as finding the last day of the previous month above.

 

int currentquarternum = (date.Month -1) / 3 + 1; DateTime firstofquarter = DateTime(date.Year, 3 * currentquarternum – 2, 1); DateTime lastofpreviousquarter = firstofquarter.AddDay(-1);