Tuesday, October 19, 2010

Email attachments - using memory stream

In my previous post I mentioned about a task where I had to send HTML mails. In each of the emails, I also had to attach a file. The files were dynamically created and I wanted to avoid having to physically create the files on the servers, attach the files to the mail and then having to delete it.

I found that it is possible to attach files as memory streams using
Message.Attachments.Add(memoryStream, ...

But as I wrote the code to do this, I found that the size of the file been attached was always 0 kb. So back to the trouble shooting ..

I was creating the file in a different assembly and the file was been received as a memory stream. So the code looked something like this

Class A
- Get details to create the file from database
- Call a method in Class B to create the file and store the returned memory stream in local variale
- Call a method in class C to send mails and pass the local memory stream to this method

Class B
- create a new file and return the file as memory stream object

Class C
- Create a mailmessage.
- Attach the file received as memorystream parameter to the mail message
- send the mail.

Everything seemed right. I even debugged the code to ensure that the memorystream object been created in class B was not empty. I debugged to see if the memory stream received by the method in class C had all the proper content and was not empty. Again everything looked fine. So where was the problem. Various people on the internet seemed to suggest flusing the memomorystream, moving the position to 0, etc but nothing worked

I finally realized that when files are attached as a memory stream to emails, the stream needs to be open. So first I tried by not closing the stream in Class B. But that did not work. So in class C before attaching the file to the mail message, I created a new stream using the same stream I got as a parameter, like this

MemoryStream memoryStream = new MemoryStream(pMyStream.ToArray());
MyMailMessage.Attachments.Add(new Attachment(memoryStream, "Name.pdf", MediaTypeNames.Application.Pdf));


and that worked !!

Line Breaks does not appear in HTML emails

Its been a looong time since my last post. That doesn't mean that I have been idle and not working :-). Just that I have been busy (which is good) and also postponing my task of updating this blog (which is bad).

There have been various issues that I have faced in the last year or so and solutions I found out the hard way which I want to write about and hopefully, I get it done sooner than later.

Anyway to start of, I will start of with a very trivial issue that some of you might have never noticed, but something which stumped me for couple of hours.

I had a task to send HTML mails using Lotus notes and I had a tough time getting the line breaks to appear. I checked all the usual things to ensure that the mails are marked as HTML and still the line breaks would not appear.

I thought it is a lotus notes client issue until I finally found what I was doing wrong.
HTML tag for line break is <br> and not <br/>.


In HTML the <br> tag has no end tag.
But in XHTML the <br> tag must be properly closed like <br />.

Friday, April 24, 2009

VS2008: Error while setting the property of a custom web control - An unhandled exception has occurred

You might see this error when you create a custom web control which has a property that you would like to set in the web page that consumes the control.
An unhandled exception has occurred. 'value' could not be set on 'propertyName'

I had created lots of custom controls in VS 2005 and creating custom properties for these controls was pretty straight forward. So I was surprised when i saw this error. I tried various things to find the reason and why the value was not getting set. Finally i gave up and started searching the net and finally got this link
http://www.west-wind.com/Weblog/posts/484172.aspx

this seemed to a bug with VS 2008 and SP1 and till date there is no solution. The only option is to close VS and open it again. But again this is a problem with the IDE, you can still compile the project and run it and it will not throw any compilation error nor show any error while accessing those properties you set on your custom control.

For those who are interested, Rick (whose blog I have referenced above) also has a issue ticket raised with microsoft which is marked as resolved, but the patch mentioned also seems to be buggy (read the comments in the link given below)
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=361826

Comments from the above link

>>>> Hi, I installed the hotfix: KB961847 - "Error creating control- [text] property" ASP.NET server cntls in VS the problem still there? can anyone tell me if i got the wrong hotfix? or is there any hotfix i need to install as well?
Posted by NatureNZ on 4/23/2009 at 2:56 PM

>>>> and the hotfix seems broke the web user control as well, i had a web user control uses standard asp controls and ajax control. it was working well in design time and now it is got the same error again.
Posted by NatureNZ on 4/23/2009 at 3:38 PM

Active directory queries

I had to spend lot of time trying to figure how to write queries on active directory using SSIS. I searched the internet for quite some time with no concrete examples. I did find examples using scripts but none for querying using ADO objects in SSIS. So I thought there might be others like me out there who might need some help .. so here goes

some of the Field names
- givenName = First name of user
- sn = Last name of user
- memberof = list of groups that the user belongs to
- cn = Display name
- objectGUID = Unique value for each record
- samAccountName = windows Login Name

The "FROM" clause would need to contain the complete domain controller name
so if you domain is called "corp.company.us.com", then your from clause would be like this
select field1, field2 from
FROM 'LDAP://DC=corp,DC=commpany,DC=us,DC=us'

if you want to fetch only the users you will need to specify a where clause like WHERE objectClass='user'

I had a requirement where I had to fetch users belonging to a particular group. I had a lot of problem finding this query. I finally learned that your where clause needs to have the whole heirarchy of the group specified. For eg, If you want to find all users in a Group called "Finance" your where clause needs to include

> memberOf = 'CN=Finance,DC=corp,DC=commpany,DC=us,DC=us'

Now if the department is within a Orgnization unit or OU called "AllUsers", then qour query needs to specify that too
> memberOf = 'CN=Finance,OU=AllUsers,DC=corp,DC=commpany,DC=us,DC=us'

Similarly you need to first check how the groups, users are created within your active directory and make changes to your query .. do remember to add the domain controller information too ..

Sample query finding all users within finance group where the finance group is plaed within a OU=Allusers

select cn
FROM 'LDAP://DC=corp,DC=commpany,DC=us,DC=us'
WHERE objectClass='user'
and memberOf = 'CN=Finance,OU=AllUsers,DC=corp,DC=commpany,DC=us,DC=us'

Hope this helps someone out there ..

Wednesday, March 25, 2009

Querying Active directory - how to fetch more than 1000 records

I had developed and tested a SSIS package which queried active directory and imported the users into a SQL server table. This was working fine till I deployed this on the client server. Some of the AD users were not getting imported. The users that were not been imported also has the same attributes and belonged to the same OU and domain as the users that were successfully imported. So I got confused and started investigating.

After some hours of various changes to the package and testing, I noticed that only 1000 records were been fetched every time. This surprised me and so I changed the query to fetch only one user which was not getting imported earlier (realised later, that this should have been my first thing I should have tested). This user now got successfully imported. So I concluded that issue was indeed with the records been limited to just 1000.

So now I started searching the internet for a solutions to this wierd problem. There were various solutions where the pagesize could be set when you user directory service objects but I could not find a solution on how to set the pagesize when queried through SSIS. So I started looking whether there is any policy that is set on active directory server and whether it is defaulted to 1000. This is when I found this article
http://support.microsoft.com/default.aspx?scid=kb;en-us;315071&sd=tech

Using the instructions in that article, I did the following
1. At the Ntdsutil.exe command prompt, type LDAP policies, and then press ENTER.
2. At the LDAP policy command prompt, type connections, and then press ENTER.
3. At the server connection command prompt, type connect to server , and then press ENTER.
4. At the server connection command prompt, type q, and then press ENTER to return to the previous menu.
5. At the LDAP policy command prompt, type Show Values, and then press ENTER.

You will see all the values set and can confirm whether the MaxPageSize is set to 1000

This is what Microsoft says about "MaxPageSize"
MaxPageSize - This value controls the maximum number of objects that are returned in a single search result, independent of how large each returned object is. To perform a search where the result might exceed this number of objects, the client must specify the paged search control. This is to group the returned results in groups that are no larger than the MaxPageSize value. To summarize, MaxPageSize controls the number of objects that are returned in a single search result.
Default value: 1,000

We can change this value by running the command
Set MaxPageSize

I am yet to test this on the client's server and will get back whether this helped in solving the problem or not. But this looks promising :-)

Friday, March 13, 2009

WCF - "The client was unable to retrieve service metadata. Make sure the service is running and exposing metadata."

So as you can see, not I have moved onto writing code in framework 3.5 and learning the way around WCF, WPF etc ..

I am in the processes of designing and developing a application using SOA and for that purpose, trying to create the data layer as service. Now why this is been planned has a service has its own reasons and maybe I can explain it sometime later. After creating a simple WCF service, I tried to test it using the default client tool provided by VS2008, I kept getting this error "The client was unable to retrieve service metadata. Make sure the service is running and exposing metadata."

I looked and cross-checked every detail and could not locate the issue. After a couple of trial and error, I noticed that one of the contract defined for the endpoint did not have the complete namespace. I had changed the namespace of contract class and I think I had reassigned the contract using the WCF configuration tool and suprisongly, it had not added the complete namespace. Anyway, correcting this namespace cleared the issue.

So you get a similar error, check the namespace for each of the component within the app.config by opening it within the VS IDE and not within the WCF configuration tool.

Monday, December 15, 2008

Sharepoint, MOSS custom project/solution

I had some work recently in creating a custom solution for sharepoint and I had never worked in sharepoint before. I thought just like you find a lot of solutions and books of other technologies, I would be able to find similar things for sharepoint too .. But sadly that was not the case. There are lots of artcles, books on sharepoint administration/customization, but very less on actual development. You will find examples for creating web parts, adding custom lists etc. But my requirement has something more than all this

I had to create a package which could be given to a client, who could then install it into his sharepoint server. Then my new sharepoint "site" must be added as a "site" within sharepoint and the users must be able to see a customzed solution which queries my database and does various other things ..

This involved ..
- creating a solution
- creating a package
- adding custom web parts
- adding these custom web parts to the "default.aspx" page
- installing this package as a "solution" in sharepoint
- having this installed soltuon as a "template" in the template list while creating new "site"
- after creating this new site, the site must have my setting for the default.aspx page and follow my styles defined

How did I do all of these. Hopefully I get time to write it soon .. If there is anyone out there who needs a answer right now, do write to me .. or I will hopefully post all that I did in the next coupld of weeks

I am not sure whether the approach I took was the best one, but at least it worked for me ..

Rejo

SSIS - debug a "script component" control

If you are reading this, you might also have faced a situation where you added a breakpoint and thought of debugging a script component in SSIS package ..

Ok, I found this is not possible. At least I could not do it in SQL 2005. Maybe its possible in 2008. Do note that you can debug scripts in a "Script task" control but not within a "script component" control within a data flow section.

I tried everything .. changing the "Precompile" property to false/true, changing the script control's name (in the design script window - changed the default generated control name from ScriptComponent_7dac1823375d4ad0bddf242bed9e1391 to ScriptComponent) etc .. but nothing worked ..

So maybe this post will save someone's time .. I copied my code to script task and I could manage to debug part of the code (the part I needed to check) .. after that I deleted the script task and returned back to my original flow/code of using the "script component"

Rejo

System.Object(), SSIS, Active directory and MemeberOf property

For the last couple of months I have working on sharepoint solutions and one of the requirement involved in fetching all users and groups from active directory. The data fetched had to be then inserted into a local SQL databaseb. As this information changes with time, the process had to be run once daily. So I opted on using SSIS to automate the whole process

It seemed pretty straight forward. I used a OLEDB connection of "Microsoft data services" to read the data from active directory. As a test I fetched couple of fields like the cn, name etc and everything worked fine, till I decieded to get the groups that the users belong to. I knew that it would be part of the "memberof" property. I used the same approach and I noticed that value gets inserted as "System.Object[]" into the database. I figured out that the value is returned as a blobcolumn and anyway I tried to parse it, it always gave me the same value. I tried

Dim lByte() As Byte = CType(dataRow(0), Byte()) .. where datarow(0) is the memberof field
System.Text.Encoding.Unicode.GetChars(lByte)

... also tried converting the column to string, collection, byte etc etc ..

and many other options .. all gave me the same result or an error .. I was really getting frustrated and I searched the net for solution. There are some examples on using SSIS and active directory and no where do they talk about how to read value from this column. So I came back to trying it on the own. I wanted to check the type of this column. But I could not add a breakpoint into a "script component" (and that is another story) .. I learned that I could add a breakpoint into a "script task" and so I copied my code over there and added breakpoint to see what data is fetched.

I saw that the column actually contains a array value. I had never seen this before .. The content of a single column looked like
(0) CN=CN1,OU=OU1,DC=corp1,DC=corp2
(1) CN=CN2,OU=OU1,DC=corp1,DC=corp2
(2) CN=CN3,OU=OU1,DC=corp1,DC=corp2

so i converted the column value to "system.array". and got the information that I needed ...

Hope this helps some people out there .. and not have to spend hours or days looking for a solution.

Rejo

Monday, June 2, 2008

Mapping varchar(max) - using micorosoft application data blocks (No mapping exists from DbType .. to a known SqlDbType ....)

I have been happily using application blocks for various tasks in my project and the data blocks was one of them. I had code like this which worked fine ..

Dim lDatabase As Database = DatabaseFactory.CreateDatabase()
Dim lCommand As DbCommand = lDatabase.GetStoredProcCommand("dbo.pr_service_WriteLog")
lCommand.CommandType = CommandType.StoredProcedure
'-- add the parameters
lDatabase.AddInParameter(lCommand, "@CreatedOn", SqlDbType.DateTime, DateTime.Now)
'-- add the error type
lDatabase.AddInParameter(lCommand, "@LogType", SqlDbType.VarChar, EntryType.ToString)
lDatabase.AddInParameter(lCommand, "@LogType", SqlDbType.VarChar, lLogBase.Type.ToString)
'-- add the message
lDatabase.AddInParameter(lCommand, "@LogMessage", SqlDbType.VarChar, lLogBase.Message)

lDatabase.ExecuteNonQuery(lCommand)

This worked fine for quite sometime till I had a new requirement to write a SP which had to insert into a table a fields with the data type defined as varchar(max). To apss this new type from the UI to SP I tried
lDatabase.AddInParameter(lCommand, "@NewParam", SqlDbType.text, MyValue)

It gave the error "No mapping exists from DbType UInt16 to a known SqlDbType." ..
So I tried various other types like Nvarchar etc etc .. but all failed .. Then I started reading about the data types supported by the data block and I came to realise that instead of using SQLDbType, i could use DBtype directly. So I tried DBtype.string and it worked !!!

Hope this helps someone who might get stuck in a similar area ....