Friday, March 20, 2009

The Right Way to Upload a file using FtpWebRequest class

There are always a bad way to do things and a good way to do it, I was reminded with that today after fighting with issues related to FtpWebRequest class !

I want to focus my article today about the how to specifically call the "GetRequestStream" method of the "FTPWebRequest" class. If you are not aware of the usage of this method, basically you use it to start writing to a buffer stream to upload a file from a source to a destination server. The following is the BAD DO NOT ATTEMP way of calling this method: I have highlighted the bad code in red below:


//Create a FTP Request Object and Specfiy a Complete Path
FtpWebRequest reqObj = (FtpWebRequest)WebRequest.Create(_completeFTPPath);
//Call A FileUpload Method of FTP Request Object
reqObj.Method = WebRequestMethods.Ftp.UploadFile;
//do not keep the connection after uploading the file
reqObj.KeepAlive = false;
//If you want to access Resourse Protected You need to give User Name and PWD
reqObj.Credentials = new NetworkCredential("username here", "password here");
//FileStream object read file from Local Drive
byte[] buffer = File.ReadAllBytes(_localUploadFullPath);
reqObj.Proxy = null;
reqObj.GetRequestStream().Write(buffer, 0, buffer.Length);
reqObj = null;


why this is bad: couple of things:
1- it cause the uploaded file to "keep writing" into the stream without finishing file upload!
2- on the receiving end, the inetinfo.exe "locks" the file and you cannot do anything with the file (which is not complete anyway) until you either kill inetinfo.exe or let it release the file after few minutes.

Below is the right way to do it:
Stream s = reqObj.GetRequestStream();
s.Write(buffer, 0, buffer.Length);
s.Close();

so we created a stream object that we can really control, once you get the stream back, you can write to it, and then call the close method to release the resources associated with ftp.

this is it, it's a small trick but it save you a lot on debugging and falling into a big trab.

Tuesday, March 10, 2009

SSIS: Using a Connection from the Connection Manager in your Script Task is Tricky!

In a SSIS package I created couple of days ago, I was trying to minimize the number of connection strings / objects in the package so that I can have less "values to configure" in the SSIS package config files.
In the package, I had a single OLEDB connection in the connection managers window, and I did the infamous access of the connection inside the scipt task hoping I can reuse, the error I got was:

"Unable to cast COM object of type 'System.__ComObject' to class type 'System.Data.OleDb.OleDbConnection'."

so I did some search and found this thread from technet
http://social.technet.microsoft.com/Forums/en-US/sqlintegrationservices/thread/7d9b3a46-9f90-4886-8a25-acabaf5d6a3f/

read the last post:
"Correct, if you want to use the connection object in a script, it must be ADO.NET, not OLE-DB, so that means two for you. The alternative is what the other posted attempted, using the connection string from an OLE-DB connection, to initialise a .NET connection object, but with the limitation of no password. if you use only integrated security it is a poissible solution."

So, I belive integration of connections between the package and the child scipt task still needs some work on the microsoft side. because now you have to either create two connections, one of type OLEDB and one of type ADO.Net, which will cause two config values in the ssis config file.
Or do it like what I did:
I created a package variable to hold the connection string and then I create my own object in the script task from this connection string, not that straightforward but the best I can do now.

happy ssis programming!
-Tamer

Thursday, March 05, 2009

Sharing libraries between Existing Projects and SSIS.

Hi all ! I have been playing with SSIS for the last few weeks. The package I was building was sophisticated and I had to reuse some of the code that I had in other .net library projects.

In SSIS Script Task, to reference an external library, you need to add the library to the GAC so it can find the binary at runtime. If you go that route, you will have to add a strong key to the existing library, right? will that's what I did, and it did not take me that long to figure out that created problems for me ! here is a simple example:

1- .net Projects 1 references Library Lib1, no strong keys, and dll of Lib1 is moved along with Project 1 when I do a complie.

2- SSIS needs to reference the library. So I add strong key to Lib1, recompile, and add to GAC.

3- now SSIS is happy.

4- Project 1 now does not have a copy of the DLL, visual studio automatically does not include Lib1 in Builds because you are not supposed to call it this way now, you need to move how you call Lib1 to the GAC way.

5- once Lib1 added to the GAK, and once you add a reference to the GAC assemply in the app.config, Project 1 will work again.

The question is, what if you do not have just one Project 1? what if you have 10 projects that reference Lib1, are you going to change all of them because of SSIS, hell no, I will not personally do that! ,,,

Easiest route is to find a way to directly use the code from Lib1 in SSIS script task, in my case Lib1 code was available so it was easy copy couple of .cs classes to the Script Task in the SSIS package, and Boom, I immediatly removed the reference to Lib1 from SSIS, and lived my life without strong keys / GAC stuff...

if you have a different way of doing it, let's know!!

Monday, March 02, 2009

Issue when Adding a reference to BIDS 2008

I was working today on a SSIS project using Business Intelligence Development Studio 2008 and I created a script task with vb.net as the default language. Then add some code and references to .net dlls.
Close the task, did something in the package, then I went back to the Script task and things disappeared, so I was upset for a moment there because of lost code. So I tried to add the reference again to my dll and it gave the message:

"no template information found. See the application log in Event Viewer for more details".

opened event viewer and found the following error in the application log:

The global template information is out of date. Regenerate the templates by running 'VSTA.exe /installvstemplates' or reinstalling the application.

I tried both:
1- ran VSTA.exe /installvstemplates and devenv.exe /installvstemplates: did not solve the issue
2- un/re installed VS.net 2008, did not do it either.

so I thought I may try to drop in a Script Task that is in a diff language, so I tried C# and adding reference in the VSA worked great ! so somthing looks corrupt on my side now with vb.net inside VSA. will tackle this issue later but at least I can get back to development to recover lost hours :)..

have a good working day!!