Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Saturday, March 8, 2008

Expose ActiveX Controls to Silverlight

So I recently (yesterday to be exact) gave a presentation on Silverlight Security. My overall conclusion was that, yeah, it was pretty darn good. I did, however, have a couple ideas on ways to circumvent some small bit of the protection primarily using JavaScript. It ended up that I didn't even need the JavaScript and could just use the HTML DOM.

I can't post the code because I'm not at liberty to distribute the ActiveX controls I used to test it but I can (and have below) post the gist of it.

Now I do have to put a disclaimer in before anyone starts in on me, this is NOT a Silverlight hack and could very easily be ported into any other webpage using simple JavaScript, not only that but it isn't necessarily a bad thing.

Remember the key is the access to HTML DOM which is the exposure point.

Also, remember that the ActiveX control has to be made available to the DOM to be accessable... so the user must download it and install it which, by the way, is ABSOLUTLY not possible to do through Silverlight.

So on with the code...

The first step, obviously, would be to have a Silverlight app open in VS.

Go to your html host page ([MyApp]TestPage.aspx or the like) and add an object reference to the html source:

<object id="MyCoolActiveX" classid="CLSID:123E1234-12AB-123A-AB1D-12341234ABCD"></object>

 
Got that setup? Okay, now we need to get a reference to that object in Silverlight.

HtmlDocument doc = HtmlPage.Document;
HtmlElement MyCoolActiveX = doc.GetElementById("MyCoolActiveX");

 
Hmm... that wasn't hard, but how do I call into the control when all I have is an HtmlElement?

object result = MyCoolActiveX.Invoke("DoSomething");
return (string)result;

 
In my case the expected result is a string so I do a cast before returning the value.

Not too difficult huh? I have a cool little ActiveX control that lets me get a list of all the system processes and it's working great.

Wednesday, October 3, 2007

Linq to Sql - Entities As Static Resources?

Here is what I would like to have:


public class WorldCountries
{
public static Country China = new Country(new Guid("6d4b5217-6fe6-11dc-8314-0800200c9a66"), "China");
public static Country Mexico = new Country(new Guid("6d4b5219-6fe6-11dc-8314-0800200c9a66"), "Mexico");
public static Country UnitedStates = new Country(new Guid("6d4b521a-6fe6-11dc-8314-0800200c9a66"), "United States");
 



public static List Countries
{
get
{
List defaultValues = new List();
defaultValues.Add(China);
defaultValues.Add(Mexico);
defaultValues.Add(UnitedStates);
return defaultValues;
}
}
}

public class UnitedStates_States
{
public static State Alabama = new State(new Guid("4f4588b0-6fe6-11dc-8314-0800200c9a66"), WorldCountries.UnitedStates, "AL", "Alabama");
public static State Alaska = new State(new Guid("4f4588b1-6fe6-11dc-8314-0800200c9a66"), WorldCountries.UnitedStates, "AK", "Alaska");
public static State Arizona = new State(new Guid("4f4588b3-6fe6-11dc-8314-0800200c9a66"), WorldCountries.UnitedStates, "AZ", "Arizona");
public static State Arkansas = new State(new Guid("4f4588b4-6fe6-11dc-8314-0800200c9a66"), WorldCountries.UnitedStates, "AR", "Arkansas");
public static State California = new State(new Guid("4f4588b5-6fe6-11dc-8314-0800200c9a66"), WorldCountries.UnitedStates, "CA", "California");
 



public static List States
{
get
{
List defaultValues = new List();
defaultValues.Add(Alabama);
defaultValues.Add(Alaska);
defaultValues.Add(Arizona);
defaultValues.Add(Arkansas);
defaultValues.Add(California);

return defaultValues;
}
}
}
  

Then I can CreateDatabase() on my data context and make a call to a function like this:


public void AddAllDefaultValues()
{
// Add world countries first because all relations depend on them
AddNewValues(_DataContext.Countries, WorldCountries.Countries);
// Add states by country
AddNewValues(_DataContext.States, UnitedStates_States.States);
}
 


public void AddNewValues(Table Table, List Values)
where TEntity : class
{
if (Table.Context != _DataContext)
{
throw new Exception("Table must be in the same context as the DefaultValueManager");
}
var currentValues = from values in Table
select values;
List currentValuesList = currentValues.ToList();
IEnumerable valuesToAdd = Values.Except(currentValuesList);

try
{
Table.AddAll(valuesToAdd);
_DataContext.SubmitChanges();
}
catch (InvalidOperationException ioe)
{
throw ioe;
}
}
  


So far so good. Everything seems to be working, unit tests verify that my database is created, check that the default values have indeed been populated and are happy.

Now I get into my application and I want to create a new State entity, so I new up the object, call add on my data context, submit changes and... error... huh?


"System.Data.SqlClient.SqlException: Violation of PRIMARY KEY constraint 'PK_dbo.Countries'. Cannot insert duplicate key in object 'dbo.Countries'."
  

Here some example code (copied from failing unit test):


State expected = new State(new Guid("694df2b2-7002-11dc-8314-0800200c9a66"), WorldCountries.UnitedStates, "TS", "Test State");

_DataContext.States.Add(expected);
_DataContext.SubmitChanges();
  


The data context is stashed in a static variable in the test class, passed to the manager class that does the DatabaseCreate and AddAllDefaultValues calls.

The same data context is then used in the tests to perform the same operation against the same objects... what's going on?

Here is how I can get around this, but it's far from ideal and renders all the static elements useless:


var countries = from c in _DataContext.Countries
where c.CountryName == "United States"
select c;
Country country = countries.SingleOrDefault();

State expected = new State(new Guid("694df2b2-7002-11dc-8314-0800200c9a66"), country, "TS", "Test State");

_DataContext.States.Add(expected);
_DataContext.SubmitChanges();
  


A comparison between the static entities does reveal some differences but I haven't (yet) identified the key item(s) but the net result is this statement attempting to execute and re-add the country which is what causes the Primary Key constraint to break.


INSERT INTO [dbo].[Countries]([CountryId], [CountryName]) VALUES (@p0, @p1)
-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [6d4b521a-6fe6-11dc-8314-0800200c9a66]
-- @p1: Input String (Size = 13; Prec = 0; Scale = 0) [United States]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
  

[Copied from output ala Kris Vandermotten]


The only idea that I have at the moment (untested) is to expose each item instead as a static property and doing a lookup and return on demand but it seems to me that there should be a way to enable this with some state flag modifications to the static entities or something.

Tuesday, October 2, 2007

Linq to SQL - UniqueIdentifier Issue

Exploring new technologies (especially betas) is always good fun.
One of my current toys is DLinq also known as Linq to SQL.
Let me just say, this stuff is pretty cool!

There are a couple of interesting scenarios to explore.
1) starting with an existing data base, one can use Linq to SQL to generate objects to match your database schema pre-generated with all the
necessary attributes and associations. The Linq to SQL DSL supports drag and drop for tables and stored procs and does some cool auto-association
mappings by reading into the foreign key relationships defined in the schema.
(I've found that it does require some re-naming post-gen for plurality issues)

2) Starting with a set of related objects, one can markup the objects with the appropriate attributes to allow Linq to bind them to data sources
with compatible schemas.

One thing that I find very exciting with either approach is the CreateDatabase() and DeleteDatabase() options off the DataContext.
I 'may' write another post to cover this in more detail but think on this:


[In ClassInitialize]
Once the DataContext is definied you can instantiate a new copy with a connection string pointing to an Express database that doesn't exist.
A simple call to CreateDatabase() and now you have a blank database with a shema that supports your objects.
Add some object with known values via DataContext.TableName.Add(Object).

[In TestMethod]
* Write some unit tests using your Linq enabled objects *

[In ClassCleanup]
A final call to DeleteDatabase()

Use a different database name for each Unit Test Class and it becomes order independant.


That being said, the real reason I decided to write up this post was because of a confusing
error message I was getting that took SEVERAL hours to finally track down.

So in the true blogging spirit here is the Problem/Solution (hack till rtm) that seems to be working for the moment.

The Auto-gen code for a table schema that includes a UniqueIdentifier Guid Key / Identity Column is fubar at the moment.
My starting configuration was (key properties):


Type: System.Guid
Auto Generated Value: True
Auto-Sync: Never
Primary Key: True
Read Only: True
  

Now, this configuration works great if you're using an int identity column but with UniqueIdentifier, something goes terribly wrong:

A first chance exception of type 'System.Data.SqlClient.SqlException' occurred in System.Data.Linq.dll
ExMessage: Explicit conversion from data type uniqueidentifier to decimal is not allowed.

  

This took me a long time to track down since the sql generation happens inside of my DataContext and for inserts I didn't see any
way to get access to the executing sql (no... I didn't think to SQL trace, can't see the forest through the trees or some such).
Then I stumbled across a couple very informative posts in rapid succession.

First, I found that I wasn't alone and simply mixing up config after reading this post by WooBoo.
In the comment our friend WooBoo makes reference to a work around (hack) but doesn't go into implementation:

'I can assign new guid to ID columns just after creating new instances but it adds new meaningless lines of code…'

Well you can't add it directly into a generated class because it will just get overwritten... we'll come back to this.

Second, I found a neat little class that lets you dump the DataContext log to the debug window!
Thanks to Kris Vandermotten for the contribution as it made the following easily available:

Using our cool new log tool here is the sql that was generated for my starting configuration:


INSERT INTO [dbo].[Topics]([TopicName], [Description], [IsGlobal], [IsApproved], [IsActive]) VALUES (@p0, @p1, @p2, @p3, @p4)

SELECT [t0].[TopicId]
FROM [dbo].[Topics] AS [t0]


WHERE (CONVERT(Decimal(29,4),[t0].[TopicId])) = (SCOPE_IDENTITY()) <-- this line is bad!!


-- @p0: Input String (Size = 7; Prec = 0; Scale = 0) [ASP.Net]
-- @p1: Input AnsiString (Size = 8; Prec = 0; Scale = 0) [My Topic]
-- @p2: Input Boolean (Size = 0; Prec = 0; Scale = 0) [True]
-- @p3: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p4: Input Boolean (Size = 0; Prec = 0; Scale = 0) [True]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
  

Turning off the Auto Generated Value flag doen't seem to help because then the key is a null guid:


INSERT INTO [dbo].[Topics]([TopicId], [TopicName], [Description], [IsGlobal], [IsApproved], [IsActive]) VALUES (@p0, @p1, @p2, @p3, @p4, @p5)

-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [00000000-0000-0000-0000-000000000000] <-- this won't work so well either

-- @p1: Input String (Size = 7; Prec = 0; Scale = 0) [ASP.Net]
-- @p2: Input AnsiString (Size = 8; Prec = 0; Scale = 0) [My Topic]
-- @p3: Input Boolean (Size = 0; Prec = 0; Scale = 0) [True]
-- @p4: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p5: Input Boolean (Size = 0; Prec = 0; Scale = 0) [True]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
  

The Auto Generated Value flag does however set you up to implement your own Id generation scheme using partial classes.
I'm defaulting here to a simple NewGuid() approach but really anything could be used here, think GUID factory that guarantees unique values
by incrementing some of the byte values or that derives from a full System.DataTime converted to GUID.

Create a new class file using the same name as your Table Mapping Object and in the same NameSpace and add something similar to the following:


public partial class Topic
{
partial void OnCreated()
{
_TopicId = Guid.NewGuid();
}
}
  

This takes advantage of some of the built in extensibility features of the generated partial classes to extend new functionality OnCreated which yields the following:


INSERT INTO [dbo].[Topics]([TopicId], [TopicName], [Description], [IsGlobal], [IsApproved], [IsActive]) VALUES (@p0, @p1, @p2, @p3, @p4, @p5)
-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [3220b7e7-3d69-4d64-876a-5d20b74e5344]
-- @p1: Input String (Size = 7; Prec = 0; Scale = 0) [ASP.Net]
-- @p2: Input AnsiString (Size = 8; Prec = 0; Scale = 0) [My Topic]
-- @p3: Input Boolean (Size = 0; Prec = 0; Scale = 0) [True]
-- @p4: Input Boolean (Size = 0; Prec = 0; Scale = 0) [False]
-- @p5: Input Boolean (Size = 0; Prec = 0; Scale = 0) [True]
-- Context: SqlProvider(Sql2005) Model: AttributedMetaModel Build: 3.5.20706.1
  

And now it works.

Friday, June 1, 2007

Generic Message Bus

So it has been a bit over a month since my last post, for shame!

I was writing an application using a MVP pattern and was contemplating the mechanism for components to bubble status info and other types of messages up to each other and also to the main container form (for a win app).

The first step was to create a container type to hold the message that I want to pass around. Because the message bus needs to be able to notify observers of new messages I derived the message container from the base EventArgs class as such:

public class MessageBusEventArgs<T> : EventArgs
{
private T _message;

public MessageBusEventArgs(T Message)
{
_message = Message;
}

public T Message
{
get
{
return _message;
}
}
}

 
Now the real value of a message bus is to allow any interested parties to register / unregister from a single source. In order to accomplish this we need a threadsafe singleton implementation for the actual MessageBus:

public class MessageBus<T>
{
private static MessageBus<T> _instance = null;
private static readonly object _lock = new object();

protected MessageBus()
{
}

public static MessageBus<T> Instance
{
get
{
lock (_lock)
{
if (_instance == null)
{
_instance = new MessageBus<T>();
}
return _instance;
}
}
}
}

 
So now we have a very usefull shell that does nothing. In order to allow interested parties to register to be notified of a new messages we need to add an event register. And finally we need a method to allow message senders to broadcast the messages out. To implement this we add the following to the MessageBus class:

public event EventHandler<MessageBusEventArgs<T>> MessageRecieved;

public void SendMessage(object sender, T Message)
{
if (MessageRecieved != null)
{
MessageRecieved(sender, new MessageBusEventArgs<T>(Message));
}
}

 
Okay, now we have a working MessageBus.
Without the generic on the classes we would have to create one of these for each message type that we want to handle but with the generic we are able to handle any type that the end user can dream up.

For anyone not familiar with generics, the compiler creates a completly separate definition of the generic class for each generic type used with it.
For example:

Type gtMessageBusInt = typeof(MessageBus<int>);
Type gtMessageBusString = typeof(MessageBus<string>);
Type gtMessageBusInt2 = typeof(MessageBus<int>);

gtMessageBusInt != gtMessageBusString
gtMessageBusInt == gtMessageBusInt2

 
It is exactly this property of generics that allows the message bus to enable opt in registration for each type of message.

This post is getting a bit long now so I'll end here and follow up shortly with an implementation example using the MessageBus<T>.