Brian Biales

because blogging is just the easiest way to remember things

  Home  |   Contact  |   Syndication    |   Login
  23 Posts | 0 Stories | 26 Comments | 9 Trackbacks

News



Archives

Post Categories

.NET Development

Open Source and FOSS topics

Patterns And Practices

Web Development

Windows Administration

Monday, February 11, 2013 #

I was very happy with Intellisense in SQL Management Studio 2008, it worked great.  So I was very surprised to have so many issues with it when I installed the 2012 version.  First of all, it seems to take forever for it to load/cache database objects that used to be available almost instantly.  With the 2012 version I can open a new query window and start typing and I don’t expect any help right away.  Sometimes it takes minutes before I get any help.  And my databases are not very large or complicated.  But that’s not even the worst of it.

Let’s take a *very* simple example.  Assuming you have a table in your currently selected database, try typing the following in both 2008 and 2012 versions:

SELECT * FROM MyTable Where MyTable.

When I typed this in SSMS 2008, a drop down list of my column names appeared instantly.

When I typed this in SSMS 2012, nothing happened.  So I pressed Ctrl-J to try and get it to work.  Instead, what I typed last (MyTable.) got a red underline, indicating a syntax error was discovered by Intellisense.  So I hovered my mouse over it, and it said:

“An expression of non-boolean type specified in a context where a condition is expected.”

Not very helpful.  Not sure why Intellisense no longer understands that since the last thing I typed was a “.” and I’m asking for some help, that perhaps I want a list of columns and not the current compilation state of my incomplete statement.

I have SSMS 2012 version 11.0.3000.0  which is at Service Pack 1.  I hope they fix this soon, Meanwhile I’m going back to SSMS 2008.


Monday, January 7, 2013 #

I’ve been fighting this issue for a long time, and just the other day discovered the solution to my problem.  Here is the issue…

My laptop is connected to my home / work / internet via its wireless (WiFi) adapter.  But I test trunk mounted modems that plug into the Ethernet port.  These often use “private” APN’s, and have no access to the internet. But when I plug them in, they use DHCP and define a default gateway to go through the WAN modem.  Great for most people, but because Ethernet is faster than WiFi, the OS automatically assigns the Ethernet gateway higher priority, because it is “faster”.  So a lot of connections go dead once I plug the modem in.

I tried using ROUTE CHANGE, and even ROUTE DELETE / ROUTE ADD to give my WiFi adapter’s gateway priority.  The commands let me specify a Metric value, but it never changed.  Well, the article below explains the default process of automatically determining the metric for gateways on a particular adapter.  Fastest one always wins.  And no overrides as long as the feature is active…

The article below explains how to “turn off” this automatic metric feature for a particular adapter, and simply hard code it.  So I set the metric for the WiFi adapter to a very low number (higher priority), then plugged the modem in.  Sure enough it added a gateway, but for the first time, its gateway had a “higher” metric than the WiFi.  So the WiFi adapter remained my default gateway even when the Ethernet cable was plugged in.  Why can’t the ROUTE command have an option to just let me even temporarily tell it which gateway metrics to use??  Ah, well, at least now I have the tool to change it when I need to…

An explanation of the Automatic Metric feature for Internet Protocol routes


Thursday, March 15, 2012 #

Do you write stored procedures that might be used by others?  And those others may or may not have already started a transaction?  And your SP does several things, but if any of them fail, you have to undo them all and return with a code indicating it failed?

Well, I have written such code, and it wasn’t working right until I finally figured out how to handle the case when we are already in a transaction, as well as the case where the caller did not start a transaction.  When a problem occurred, my “ROLLBACK TRANSACTION” would roll back not just my nested transaction, but the caller’s transaction as well.  So when I tested the procedure stand-alone, it seemed to work fine, but when others used it, it would cause a problem if it had to rollback.  When something went wrong in my procedure, their entire transaction was rolled back.  This was not appreciated.

Now, I knew one could "nest" transactions, but the technical documentation was very confusing.  And I still have not found the approach below documented anywhere.  So here is a very brief description of how I got it to work, I hope you find this helpful.

My example is a stored procedure that must figure out on its own if the caller has started a transaction or not.  This can be done in SQL Server by checking the @@TRANCOUNT value.  If no BEGIN TRANSACTION has occurred yet, this will have a value of 0.  Any number greater than zero means that a transaction is in progress.  If there is no current transaction, my SP begins a transaction. But if a transaction is already in progress, my SP uses SAVE TRANSACTION and gives it a name.  SAVE TRANSACTION creates a “save point”.  Note that creating a save point has no effect on @@TRANCOUNT. 

So my SP starts with something like this:

DECLARE @startingTranCount int
SET @startingTranCount = @@TRANCOUNT

IF @startingTranCount > 0
    SAVE TRANSACTION mySavePointName
ELSE
    BEGIN TRANSACTION
-- …

Then, when ready to commit the changes, you only need to commit if we started the transaction ourselves:

IF @startingTranCount = 0
    COMMIT TRANSACTION

And finally, to roll back just your changes so far:

-- Roll back changes...
IF @startingTranCount > 0
    ROLLBACK TRANSACTION MySavePointName
ELSE
    ROLLBACK TRANSACTION

Here is some code that you can try that will demonstrate how the save points work inside a transaction.

This sample code creates a temporary table, then executes selects and updates, documenting what is going on, then deletes the temporary table.

if running in SQL Management Studio, set Query Results to: Text for best readability of the results.

-- Create a temporary table to test with, we'll drop it at the end.
CREATE TABLE #ATable(
    [Column_A] [varchar](5) NULL
) ON [PRIMARY]

GO
SET NOCOUNT ON
-- Ensure just one row - delete all rows, add one
DELETE #ATable
-- Insert just one row
INSERT INTO #ATable VALUES('000')

SELECT 'Before TRANSACTION starts, value in table is: ' AS Note, * FROM #ATable

SELECT @@trancount AS CurrentTrancount
--insert into a values ('abc')
UPDATE #ATable SET Column_A = 'abc'
SELECT 'UPDATED without a TRANSACTION, value in table is: ' AS Note, * FROM #ATable
BEGIN TRANSACTION
SELECT 'BEGIN TRANSACTION, trancount is now ' AS Note, @@TRANCOUNT AS TranCount
UPDATE #ATable SET Column_A = '123'
SELECT 'Row updated inside TRANSACTION, value in table is: ' AS Note, * FROM #ATable
SAVE TRANSACTION MySavepoint
SELECT 'Save point MySavepoint created, transaction count now:' as Note, @@TRANCOUNT AS TranCount
UPDATE #ATable SET Column_A = '456'
SELECT 'Updated after MySavepoint created, value in table is: ' AS Note, * FROM #ATable
SAVE TRANSACTION point2
SELECT 'Save point point2 created, transaction count now:' as Note, @@TRANCOUNT AS TranCount
UPDATE #ATable SET Column_A = '789'
SELECT 'Updated after point2 savepoint created, value in table is: ' AS Note, * FROM #ATable
ROLLBACK TRANSACTION point2
SELECT 'Just rolled back savepoint "point2", value in table is: ' AS Note, * FROM #ATable
ROLLBACK TRANSACTION MySavepoint
SELECT 'Just rolled back savepoint "MySavepoint", value in table is: ' AS Note, * FROM #ATable
SELECT 'Both save points were rolled back, transaction count still:' as Note, @@TRANCOUNT AS TranCount
ROLLBACK TRANSACTION
SELECT 'Just rolled back the entire transaction..., value in table is: ' AS Note, * FROM #ATable

DROP TABLE #ATable

The output should look like this:

Note                                           Column_A
---------------------------------------------- --------
Before TRANSACTION starts, value in table is:  000

CurrentTrancount
----------------
0

Note                                               Column_A
-------------------------------------------------- --------
UPDATED without a TRANSACTION, value in table is:  abc

Note                                 TranCount
------------------------------------ -----------
BEGIN TRANSACTION, trancount is now  1

Note                                                Column_A
--------------------------------------------------- --------
Row updated inside TRANSACTION, value in table is:  123

Note                                                   TranCount
------------------------------------------------------ -----------
Save point MySavepoint created, transaction count now: 1

Note                                                   Column_A
------------------------------------------------------ --------
Updated after MySavepoint created, value in table is:  456

Note                                              TranCount
------------------------------------------------- -----------
Save point point2 created, transaction count now: 1

Note                                                        Column_A
----------------------------------------------------------- --------
Updated after point2 savepoint created, value in table is:  789

Note                                                     Column_A
-------------------------------------------------------- --------
Just rolled back savepoint "point2", value in table is:  456

Note                                                          Column_A
------------------------------------------------------------- --------
Just rolled back savepoint "MySavepoint", value in table is:  123

Note                                                        TranCount
----------------------------------------------------------- -----------
Both save points were rolled back, transaction count still: 1

Note                                                            Column_A
--------------------------------------------------------------- --------
Just rolled back the entire transaction..., value in table is:  abc


Thursday, July 21, 2011 #

I have a need for a highly responsive web page that must at least appear to be "pushed" information from the server as it happens, much like you'd see with an HTTP protocol based chat window.  The client will utilize JavaScript, and will use JQuery and its UI plugins, and will use its AJAX support to call the requests that will only return when there is data to be "pushed".

I know HTML 5 includes support for WebSockets, but I feel it is too soon to rely on them, as the spec is not yet finished and the web clients and servers are really still experimenting with the protocol.  Applications have been successfully using the long running request (or worse, polling) to essentially produce the "push" functionality desired.  There is a protocol Comet that I have read a little about, and I would consider using it if someone endorsed a great implementation of it that they have used or seen used successfully with an ASP.NET/IIS7 server side implementation.

But it seems not so terribly difficult to do on my own, although I see certain technical challenges that must be dealt with.

  1. Users must be logged on to use my service.  I planned to keep state information in Session variables, most likely tied to SQL Server rather than in memory, so that sessions stay "alive" even if IIS recycles or the thread pool recycles.  This is not a "public" app, it will have limited users and limited traffic, so the speed penalty of storing state in the DB should not be a critical issue. 

    I believe, though, that if my "long running" request accesses the Session, even just to read who is logged on before starting, it establishes a "read lock" that I cannot see how to unlock.  So while my long running query is executing, any other concurrent request from the same session (there will be many) that read the Session will be OK, but if any needs to write to the Session variables, they will be blocked until my long running request finishes, as a write lock must wait for all prior read locks to complete.  So therefore it seems that I must create my own "Session" in my own database.  And I guess I'll need to handle the locks myself if I want.  I'm pretty sure my implementation will need just a simple short term lock, for reading or writing, which will simply use a static class object and the "lock" C# keyword (using the Monitor class).  I don't anticipate needing to implement both read and write locks for my application.

  2. 2) Storing state in a database will require me to do my own processing of "expired" sessions.

  3. 3) I plan to use ASP.NET's IHttpAsyncHandler, which will spin off a thread not in the thread pool to wait until there is data to be sent back to the client.  This way long running requests will not exhaust IIS's thread pool.  I think a thread per request would be ok, although I should be able to simply register the request in a way that would allow a single background / non-pooled thread to handle all the outstanding requests.  I’ve not fully worked out the best way to approach this.  I like the single thread idea, I just need to figure out the best place to create this background thread, so it is always there when I need it.

As you can see, I am in the early stages, figuring out the best architecture, finding and reviewing examples and anticipating issues I’ll need to resolve in my design.  If anyone knows of a good example of this sort of thing, or has any suggestions based on experience, I’d love to hear it. 

[Edit 1/7/2012] 
The best solution I've found is a product called WebSync.  It works in all browsers, using the best technology available in that browser to accomplish the task.  If WebSockets are supported, it will use pure HTML5 capabilities, but if not, there are "long running query" capabilities they utilize.  The API is a pretty simple "Publish"/"Subscribe" model.  Great for .NET developers (it runs in IIS)


Thursday, June 3, 2010 #

For those who do not mix .NET C# code with legacy DLL's that use char* pointers on a regular basis, the process to convert the strings one way or the other is non-obvious.

This is not a comprehensive article on the topic at all, but rather an example of something that took me some time to go find, maybe it will save someone else the time.

I am utilizing a third party too that uses a call back function to inform my application of its progress.  This callback includes a pointer that under some circumstances is a pointer to an ANSI character string.  I just need to marshal it into a C# string variable.  Seems pretty simple, yes?  Well, it is, (as are most things, once you know how to do them).

The parameter of my callback function is of type IntPtr, which implies it is an integer representation of a pointer.  If I know the pointer is pointing to a simple ANSI string, here is a simple static method to copy it to a C# string:

private static string GetStringFromCharStar(IntPtr ptr)
{
   
return System.Runtime.InteropServices.Marshal.PtrToStringAnsi(ptr);
}

The System.Runtime.InteropServices is where to look any time you are mixing legacy unmanaged code with your .NET application. 


Wednesday, March 10, 2010 #

A client is using Openfire IM for their users, and would like some custom queries to audit user conversations (which are stored by Openfire in tables in the SQL Server database).

Because Openfire supports multiple database servers and multiple platforms, the designers chose to store all date/time stamps in the database as 15 character strings, which get converted to Java Date objects in their code (Openfire is written in Java).
EDIT: Turns out these are actually stored as BIGINT, not VARCHAR(15), which makes it a little bit simpler...

I did some digging around, and, so I don't forget and in case someone else will find this useful, I will put the simple algorithms here for converting back and forth between SQL DATETIME and the Java string representation.

The Java string representation is the number of milliseconds since 1/1/1970. 

SQL Server's DATETIME is actually represented as a float, the value being the number of days since 1/1/1900, the portion after the decimal point representing the hours/minutes/seconds/milliseconds... as a fractional part of a day. 
Try this and you will see this is true:
    SELECT CAST(0 AS DATETIME)
and you will see it returns the date 1/1/1900.

The difference in days between SQL Server's 0 date of 1/1/1900 and the Java representation's 0 date of 1/1/1970 is found easily using the following SQL:
  SELECT DATEDIFF(D, '1900-01-01', '1970-01-01')
which returns 25567.  There are 25567 days between these dates.

So to convert from the Java string to SQL Server's date time, we need to convert the number of milliseconds to a floating point representation of the number of days since 1/1/1970, then add the 25567 to change this to the number of days since 1/1/1900.  To convert to days, you need to divide the number by 1000 ms/s, then by  60 seconds/minute, then by 60 minutes/hour, then by 24 hours/day.  Or simply divide by 1000*60*60*24, or 86400000.   So, to summarize, we need to cast this string as a float, divide by 86400000 milliseconds/day, then add 25567 days, and cast the resulting value to a DateTime.  Here is an example:

  DECLARE @tmp as VARCHAR(15)
  SET @tmp = '1268231722123'
  SELECT @tmp as JavaTime, CAST((CAST(@tmp AS FLOAT) / 86400000) + 25567 AS DATETIME) as SQLTime

EDIT: or, for starting with a BIGINT:
  DECLARE @tmp as BIGINT
  SET @tmp = 1268231722123
  SELECT @tmp as JavaTime, CAST((CAST(@tmp AS FLOAT) / 86400000) + 25567 AS DATETIME) as SQLTime
 

To convert from SQL datetime back to the Java time format is not quite as simple, I found, because floats of that size do not convert nicely to strings, they end up in scientific notation using the CONVERT function or CAST function.  But I found a couple ways around that problem. You can convert a date to the number of  seconds since 1/1/1970 very easily using the DATEDIFF function, as this value fits in an Int.  If you don't need to worry about the milliseconds, simply cast this integer as a string, and then concatenate '000' at the end, essentially multiplying this number by 1000, and making it milliseconds since 1/1/1970.  If, however, you do care about the milliseconds, you will need to use DATEPART to get the milliseconds part of the date, cast this integer to a string, and then pad zeros on the left to make sure this is three digits, and concatenate these three digits to the number of seconds string above.  And finally, I discovered by casting to DECIMAL(15,0) then to VARCHAR(15), I avoid the scientific notation issue.  So here are all my examples, pick the one you like best...

First, here is the simple approach if you don't care about the milliseconds:
  DECLARE @tmp as VARCHAR(15)
  DECLARE @dt as DATETIME
  SET @dt = '2010-03-10 14:35:22.123'
  SET @tmp = CAST(DATEDIFF(s, '1970-01-01 00:00:00' , @dt) AS VARCHAR(15)) + '000'
  SELECT @tmp as JavaTime, @dt as SQLTime
EDIT: And a BIGINT is even simpler:
  DECLARE @tmp as BIGINT
  DECLARE @dt as DATETIME
  SET @dt = '2010-03-10 14:35:22.123'
  SET @tmp = CAST(DATEDIFF(s, '1970-01-01 00:00:00' , @dt) AS BIGINT) * 1000
  SELECT @tmp as JavaTime, @dt as SQLTime
 

If you want to keep the milliseconds:
  DECLARE @tmp as VARCHAR(15)
  DECLARE @dt as DATETIME
  DECLARE @ms as int
  SET @dt = '2010-03-10 14:35:22.123'
  SET @ms as DATEPART(ms, @dt)
  SET @tmp = CAST(DATEDIFF(s, '1970-01-01 00:00:00' , @dt) AS VARCHAR(15))
          + RIGHT('000' + CAST(@ms AS VARCHAR(3)), 3)
  SELECT @tmp as JavaTime, @dt as SQLTime

EDIT: Or, as BIGINT instead of varchar:
  DECLARE @tmp as BIGINT
  DECLARE @dt as DATETIME
  DECLARE @ms as int
  SET @dt = '2010-03-10 14:35:22.123'
  SET @ms as DATEPART(ms, @dt)
  SET @tmp = CAST(DATEDIFF(s, '1970-01-01 00:00:00' , @dt) AS BIGINT) + @ms 
  SELECT @tmp as JavaTime, @dt as SQLTime
 

Or, in one fell swoop:
  DECLARE @dt as DATETIME
  SET @dt = '2010-03-10 14:35:22.123'
  SELECT @dt as SQLTime
    , CAST(DATEDIFF(s, '1970-01-01 00:00:00' , @dt) AS VARCHAR(15))
          + RIGHT('000' + CAST( DATEPART(ms, @dt) AS VARCHAR(3)), 3) as JavaTime

EDIT: Or, as BIGINT instead of varchar:
  DECLARE @dt as DATETIME
  SET @dt = '2010-03-10 14:35:22.123'
  SELECT @dt as SQLTime
    , CAST(DATEDIFF(s, '1970-01-01 00:00:00' , @dt) AS BIGINT) + DATEPART(ms, @dt)  as JavaTime
 

And finally, a way to simply reverse the math used converting from Java date to SQL date.
Note the parenthesis - watch out for operator precedence, you want to subtract, then multiply:
  DECLARE @dt as DATETIME
  SET @dt = '2010-03-10 14:35:22.123'
  SELECT @dt as SQLTime
    , CAST(CAST((CAST(@dt as Float) - 25567.0) * 86400000.0 as BIGINT) as VARCHAR(15)) as JavaTime

EDIT: Or even better as a BIGINT:
  DECLARE @dt as DATETIME
  SET @dt = '2010-03-10 14:35:22.123'
  SELECT @dt as SQLTime
    , CAST((CAST(@dt as Float) - 25567.0) * 86400000.0 as BIGINT)  as JavaTime
 

Interestingly, I found that converting to SQL Date time can lose some accuracy, when I converted the time above to Java time then converted  that back to DateTime, the number of milliseconds is 120, not 123.  As I am not interested in the milliseconds, this is ok for me.  But you may want to look into using DateTime2 in SQL Server 2008 for more accuracy.
 

  


Monday, January 18, 2010 #

My Wordpress emails were being rejected by my ISP's SMTP server. I fixed this by editing wordpress\wp-includes\pluggable.php in the wp_mail()
function, the following line:
// Set to use PHP's mail()
   $phpmailer->IsMail();

Which uses the PHP mail feature,

To the following:
// Set to use SMTP mail()
    $phpmailer->IsSMTP();
    $phpmailer->Host='localhost';
 

This uses my local smtp server, but you can look at the phpmailer class and set variables here to use whatever smtp server you wish, authenticated, or not, secure or not, etc...

It would be nice if Wordpress would make all this configurable, but it looks hardcoded to me... 


Friday, June 19, 2009 #

I was speaking with a colleague earlier today about a potential threading issue in his code.  I suggested serializing access to his object to ensure two threads are not using it at the same time, as that could corrupt the processing.  Being a relative “old-timer” who’s largest mutithreading applications were written in Visual C++ v 5 and 6, I remember heavy use of the CriticalSection, and wrapping the lock/unlock of critical sections in a class to ensure that every lock eventually got unlocked.  We developed the class to ensure matched Enters and Exits after many hours of debugging deadlocks in the early development stages.  But I digress a little…  .NET has wrapped it all up for us now, and I thought I’d just right this up for the next time someone asks me about it.

The Monitor class (in System.Threading) can help synchronize access to a particular object or resource, ensuring that once a thread has access, it will remain the only thread with access until the lock is released.  To use it, create an object that is shared with all the threads that will be accessing the resource (perhaps a static member of a class they all use).  It doesn’t have to be any particular type of object.  As a matter of fact, it could be declared and initialized (in C#) as:

Object oLocker = new Object();

Now if you want exclusive access to the resource, you can use the Monitor class like this:

Monitor.Enter(oLocker);

If another thread has already “entered” for this object, your thread will block until that other thread calls Monitor.Exit(oLocker).  Many threads can be blocked at once.  When the owning thread calls the Monitor.Exit(), one of those waiting threads is allowed access.  I believe it is FIFO, but I don’t know if that is guaranteed.

A thread can actually end up calling Monitor.Enter() multiple times on the same object.  If the thread already owns the lock, then this will simply increment a lock count.  You MUST call Exit for each time you call Enter.  Otherwise you WILL cause a deadlock in your program. 

You could make sure you call Exit yourself, by using the try / finally construct. You would Call Monitor.Enter() in the try block, and call Monitor.Exit()  in the finally block.  So even if your code throws an unhandled exception, the finally code block would exit the lock. 

The C# and VB.NET languages have macros to help you ensure you unlock at the end.  C# uses lock, VB.Net uses SyncLock.

In C# you would use lock like this:

lock(oLocker)
{
    <put your synchronized code here>
}

What lock does is call Monitor.Enter() on the object in the parenthesis, and add a finally block for you at the end that calls Monitor.Exit().  This makes your code easier to read and easier to write.

SyncLock does basically the same thing in VB.NET.  The syntax is slightly different.

Here is a VB.Net example:

SyncLock oLocker
    <put your synchronized code here>
End SyncLock

 

Any code that uses lock or SyncLock (or Monitor.Enter()/Monitor.Exit()) on a particular object can run with the assurance that no other thread will interfere with it. 


Monday, May 4, 2009 #

I just found a great post at SQL Tips by Namwar Rizvi - TSQL Function to convert decimal to Hex, Octal or any other base (http://sqltips.wordpress.com/) with a great, simple function to convert any integer into a string of characters in any base from 2 through 36. 

Here it is, the comments include his post text, giving original credit for this algorithm to Itzik Ben-Gan in his book Inside Microsoft SQL Server 2005:TSQL Querying:

IF EXISTS 
(
   SELECT * FROM sysobjects
     WHERE id = OBJECT_ID(N'[dbo].[fn_decToBase]')
       AND type in (N'FN', N'IF', N'TF', N'FS', N'FT')
)
   DROP FUNCTION [dbo].[fn_decToBase]
Go
 
Create function [dbo].[fn_decToBase]
(
@val as BigInt,
@base as int
)
returns varchar(63)
as
Begin
/* From http://sqltips.wordpress.com/2009/01/12/tsql-function-to-convert-decimal-to-hex-octal-or-any-other-base/  */
/* blog text: 
SQL Tips by Namwar Rizvi
  Frequently I see the questions in newsgroups about a function to convert 
  integer value to other bases like base 2 (binary), base 8 (octal) and base 16(hex). 
  Following TSQL function, which was orginally mentioned by Itzik Ben-Gan 
  in his book Inside Microsoft SQL Server 2005:TSQL Querying, provides you the 
  ability to convert a given integer into any target base. 
  I have just updated the function with more meaningful names and added some 
  comments to clear the logic.
*/
 
  /* Check if value is valid and if we get a valid base (2 through 36) */
  If (@val<0) OR (@base < 2) OR (@base> 36) Return Null;
 
  /* variable to hold final answer */
  Declare @answer as varchar(63);
 
  /* Following variable contains all 
     possible alpha numeric letters for any valid base 
  */
  Declare @alldigits as varchar(36);
  Set @alldigits='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
  /* Set the initial value of 
     final answer as empty string 
  */
  Set @answer='';
 
  /* Loop while the source value remains greater than 0 */
  While @val>0
  Begin
    Set @answer=Substring(@alldigits,@val % @base + 1,1) + @answer;
    Set @val = @val / @base;
  End
 
  /* Return the final answer */
  return @answer;
End

Tuesday, April 21, 2009 #

[Update: 4/21/09]
I did get this to work finally.  This article clued me in:
http://www.4guysfromrolla.com/webtech/043099-1.shtml

It turns out the server.CreateObject() method takes only one parameter, the name of the object.  But the global CreateObject function takes two parameters.  The second parameter being the server on which the object should be run.  So not only did I need to add the server name as a second parameter, but I also had to use the global CreateObject() function to create the object. 

In addition, I mention below the need to change the "metabase" to allow out of proc servers.  This is no longer necessary, and was not part of the problem...

What you do need to do, though, is make sure that this is added to IIS as an "application" not simply a virtual directory.  Otherwise the global.asa file will not be run, and so the code below that creates this object when a new session starts won't be run.

Oh, and one other thing :-)  If IIS 7 is running on a 64bit machine, and you use 32 bit OCX's, you'll need to change the application pool parameter to allow 32bit code to run.

[End of Update: 4/21/09]

I have some old ASP pages that utilize a COM object, which it initializes in the global.asa file as follows:

<SCRIPT LANGUAGE=VBScript RUNAT=Server>

Sub Session_OnStart

Set Session("MyObject") = server.createobject("MyComServer.MyObject")
End Sub

</SCRIPT>

The web server (IIS) happens to run on the same machine as MyComServer.  But now I want to move the IIS to another machine.  So I tried to use DCOMCNFG on the new IIS server to specify that this COM server should be run on the machine "XYZ".  And I made sure the IIS user this app runs as is allowed to instantiate and call it.  It keeps trying to execute it locally, though...

So then I tried the following (you can do this in VB, why not ASP?).  I added a second parameter to the createobject call, to specify the server I want to connect to.  See below:

Sub Session_OnStart
Set Session("MyObject") = server.createobject("MyComServer.MyObject", "10.0.1.1") 'this is the address of my COM Server...
End Sub

This, though, causes an http 500 error to be displayed.

Does anyone have any suggestions?  I know IIS 6 needed to have the metabase altered first, by running the following, can you even do this with IIS 7?  Is there somewhere else to set this option?:

<%@ Language=VBScript %>
<%
' Get the IIsWebVirtualDir Admin Object
set vDirObj = GetObject("IIS://LocalHost/W3svc/1/Root/vdir_name")

'Enable the AspAllowOutOfProcComponenents Parameter
VDirObj.Put "AspAllowOutOfProcComponents", True

'Save the Changed value to the metabase
VdirObj.SetInfo

%>

Any comments that might help would be greatly appreciated!


Thursday, February 26, 2009 #

I've been bothered by this for a little while now.  I reboot my laptop, it connects to my router (WLAN), gets its address (as well as the DNS server's address) via DHCP.  But the machine cannot resolve any names.  Vista reports my LAN is "local only".  Diagnostics say the DNS is not working.  I used Wireshark, and discovered that when I try to resolve a name, such as when I type "ping www.google.com" at the command prompt, it sends all resolution requests to my WINS server, which of course says it has no address for it, but does not, when that fails, attempt to resolve through the DNS.  Wireshark showed no traffic on port 53 at all. 

I ran NSLookup, which reports my router IP Address as the DNS.  IPCONFIG /all shows my wireless connection has my router's IP as the DNS server.  But Wireshark shows NO traffic on port 53 going to/from the router.  What's up with that?

Eventually, many long minutes later, I don't know exactly how long I waited, it starts working...  I have no idea why.

That is, I had no idea until today.  I think I have figured this out.  I have a gigabit ethernet port on my laptop as well, which IPConfig correctly reports as "Media disconnected".  But, now I notice in Wireshark, when you list all the interfaces, my gigabit ethernet port is listed, with an IP Address defined!  I had recently plugged my computer into my router with a cable, to move some large files I wanted to move faster.  So this IP Address I see assigned to my "media disconnected" port is, of course, on the same subnet as my wireless connection.   Hmmmmm.   If Wireshark thinks there is a gigabit port with an address on my subnet, maybe Vista does too?  Maybe it's trying to reach the DNS on this faster, all but disconnected, interface? 

So I went to Control Panel/Network Connections, and disabled my gigabit port.  Interesting, the DNS issue was immediately resolved.  I rebooted, and as soon as I got an address on my wireless WLAN, it immediately says it is enabled for local and internet.  Now I'm blogging about it.  So if the problem is not permanently resolved, I'll have to update this post.

So I think I've solved the problem.  And perhaps I've discovered a bad bug in Vista (I have all current service packs and updates installed). It appears to me, anecdotally at least, that that when the ethernet port gets an address assigned, but then gets disconnected (but is still enabled), it may have some effect on your networking.

Note that I do have a WINS server hardcoded for my WLAN connection.  And it is NOT on my local subnet at home.  But it is routable (my home router has a site-to-site VPN with the office) so the WINS server was responding to the requests.  I only mention this because in other posts I found while researching this, at least one had posted an IPCONFIG /ALL result which showed something similar - the DNS was defined (as the router's address) and there was a WINS server defined as well, but on another subnet, but the DNS was not being accessed properly.  Relevant?  I have no idea.

I hope someone finds this information useful...


Tuesday, December 2, 2008 #

Ok, so this probably doesn't happen often, where some code doesn't know on what server or database it is operating on, but needs to know this information...  To be honest, I created this as I was able to logon to someone's DotNetNuke site as an admin, but did not have direct access to the website files.  The site owner asked where the database resided.  So I went to the Host->SQL menu option, which lets you run dynamic sql against your database.  And I typed this command in to discover the server and database name that DNN was using:

SELECT @@servername as ServerName, db_name() as DatabaseName

@@servername resolves to the name of the database server, and db_name() resolves to the "default" or current database.

Quite simple, I am posting it just in case someone else may find this useful some day.


Wednesday, June 13, 2007 #

Most resizing logic is either geared toward running the application in different resolutions, or in keeping a control proportionately placed on a page or with reference to other controls.  The Dock feature is great for handling a lot of your resizing needs as well.  But I've found a solution to a different resizing problem that I'll bet others have run into as well.
Let’s say I have placed three labels (or other controls) in a strip at the top of the screen, and these are resized to each be 1/3 the width of the window. But I want to make sure that the text in each (which may vary in length) remains visible in its entirety no matter what the user does to resize the window. My solution is to vary the font size when the control is resized. And I found it pretty easy to figure out what font size will allow the text to fit.  I use the preferredWidth() method (some controls use preferredSize(), but the Label uses preferredWidth) to figure out if the text inside would "prefer" to be in a control that is wider than this one.  If so, I drop the font size down a bit and test again.  Once it fits, we're done.
This is not perfect, you may need to alter it slightly for your needs. For instance, I allow the height to grow as needed if the font is now bigger. If this doesn’t work for you, you’ll have to ensure it is always tall enough for the largest font that will be used. Also, I’ve found that when using CAB Workspaces, sometimes I need to resize the height of the parent Workspace myself when the SmartPart changes size.  That could be another article some day...
Here is the code, I hope you find it useful! 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace AlwaysFitLabel
{
    ///
<summary>
    ///
The Label that always displays its text
    ///
</summary>
    public class AlwaysFitLabel :
Label
    {
        private float _maxFontSize = 16F;
// Pick a default value...
        public float maxFontSize { get { return _maxFontSize; } set { _maxFontSize = value; } }

        public AlwaysFitLabel()
        {
           
// Add a handler for the resize event, which we implement below
            this.Resize += new EventHandler(AlwaysFitLabel_Resize);
        }
        public override string Text
        {
           
get
            {
                return base.Text;
            }
           
set
            {  
// always resize it when text changes...
                base.Text = value;
                AlwaysFitLabel_Resize(this, new EventArgs());
            }
        }
        void AlwaysFitLabel_Resize(object sender, EventArgs e)
        {
           
// This function uses a temporary label to put the text with the largest font size,
           
// see if it fits, and if not, keep knocking the font size down by .5 until it does
           
// fit.  Then set the real label's font size to this newly calculated font size.
            Label lbl = new Label();
            float fntSize = maxFontSize;
            lbl.Text = this.Text;
            lbl.Font = new System.Drawing.Font(this.Font.FontFamily, fntSize);
            while (lbl.PreferredWidth > this.Width && fntSize > 0.6F)
            {
                fntSize -= 0.5F;
                lbl.Font = new System.Drawing.Font(this.Font.FontFamily, fntSize);
            }
            this.Font = new System.Drawing.Font(this.Font.FontFamily, fntSize);
            this.Height = this.PreferredHeight;
        }
    }
}


Thursday, April 12, 2007 #

I discovered an interesting issue while decorating an EventTopic subscription in my ModuleController for one of my modules.  The decoration was like this:

[EventSubscription(EventTopicNames.MessageArrived, ThreadOption.UserInterface)]
public void OnMsgReceived(object sender, EventArgs<Msg> ev)

The event is fired on a non-UI thread, and I disovered this event handler was being called on that thread, NOT on the UserInterface thread as specified in the decoration.  This decoration works fine in a View's Presenter class.  But in my ModuleController class, it doesn't.

Well, I've looked into this further, and posted my findings at the CodePlex discussion group
http://www.codeplex.com/smartclient/Thread/View.aspx?ThreadId=8956
but I'll include my findings here as well:

When I subscribe to the event explicitly like this, my event handler does indeed get called on the UI thread:

        public override void Run()
        {
            AddServices();
            ExtendMenu();
            ExtendToolStrip();
            AddViews();
            // Explicitly subscribe to this event topic
            WorkItem.EventTopics{EventTopicNames.MessageArrived].AddSubscription(
                this, "OnMsgReceived", WorkItem, ThreadOption.UserInterface);
        }

 

But when I decorate my event handler like the following, (in ModuleController.cs) this event handler gets called actually on the same thread on which it was fired (which is NOT the UI thread).

        [EventSubscription(EventTopicNames.MessageArrived, ThreadOption.UserInterface)]
        public void OnMsgReceived(object sender, EventArgs<Msg> ev)
        {
            ...
        }

 

The relevant code I found while debugging (which I could only do when I explicitly subscribe to the event, although someone who knows how could do this by stepping through the CAB code that handles the decorations...)

If SynchronizationContext.Current is null at the time the subscription is being added, then the subscription’s syncContext property will NOT get set, and I believe this is likely the ultimate issue.  You can see below the code snippet at subscription time.  Below that is a code snippet at Fire execution time, and it clearly will simply call the event handler directly on the current thread if the syncContext property was not set at subscription time.

 

At Subscription time:
In EventBroker\Subscription.cs Ln 93

         if (threadOption == ThreadOption.UserInterface)
         {
                // If there's a syncronization context (i.e. the WindowsFormsSynchronizationContext 
                // created to marshal back to the thread where a control was initially created 
                // in a particular thread), capture it to marshal back to it through the 
                // context, that basically goes through a Post/Send.
                if (SynchronizationContext.Current != null)
                {
                      syncContext = SynchronizationContext.Current;
                }
         }

At Fire time:
In EventBroker\Subscription.cs Ln 215

    private void CallOnUserInterface(object sender, EventArgs e, List<Exception> exceptions)
    {
          Delegate handler = CreateSubscriptionDelegate();
          if (handler != null)
          {
                if (syncContext != null)
                {
                      syncContext.Send(delegate(object data)
                      {
                            try
                            {
                                  ((Delegate)data).DynamicInvoke(sender, e);
                            }
                            catch (TargetInvocationException ex)
                            {
                                  exceptions.Add(ex.InnerException);
                            }
                      }, handler);
                }
                else
                {
                      try
                      {
                            handler.DynamicInvoke(sender, e);
                      }
                      catch (TargetInvocationException ex)
                      {
                            exceptions.Add(ex.InnerException);
                      }
                }
          }
    }


Monday, March 26, 2007 #

First, what happened:

I can’t believe it, but my home machine was actually hacked into this weekend.  I had installed RealVNC 4.1.1 some time ago, so I could access my machine from afar, although frankly I use RDC much more often, as it is more secure.  I just never turned VNC off…  Well, I sure should have.  See this link for information about the vulnerability in this version of Real VNC:

 

http://secunia.com/advisories/20107/

 

The screen saver always locks my desktop, it keeps the kids off the computer unless authorized.  In the morning when my wife entered the logon password as usual, she watched all the icons on the desktop disappear, all that was left was the wallpaper.  Ctrl-alt-delete did nothing.  I went to another machine to review this one to see what might be wrong, and what I found put a lump in my throat.  The event log showed many connections to VNC, and following the last one, I saw my AntiVirus and many other services being shut down.  Beyond that, nothing was logged, but clearly someone had maliciously invaded my machine!  Paranoia kicked in, and I immediately turned off the machine.  Who knew what it was doing...

 

What I did about it:

Fortunately for me, I recently started making image backups of my system hard drive.  See my blog entry about that hereI was very curious what had been changed and altered, but I didn’t want to actually run the machine in its state.  So I booted my GParted CD, and made a copy of the current C: partition to some free space on my external USB drive.  Then I used my BartPE bootable CD, and used DriveImage XML to restore the C: partition to its state the last time I backed it up (about a week earlier).  I then restarted the machine, and, after immediately changing my logon password and disabling RealVNC, I did a file by file comparison between my current (restored) image, and the copy of the image (now the G: drive) that I had made before doing the restore.  I found some odd things, if anyone wants more details, I’d be happy to share them.  I am assuming it was the hacker who changed the following files in my system directory:

            Mrt.exe

            Msscp.dll

            Ntkrnlpa.exe

            Ntoskrnl.exe

 

I am very concerned that the password my wife entered was immediately sent to the hacker.  I have no way of knowing, really.  Having caught it quickly, though, and restoring the entire image, changing my password, and eliminating the source of the hack, I am pretty confident that I have a clean machine once again.

 

What to do to avoid this in the future:

Here is what I did wrong, and what I intend to do to fix it, because this could have been avoided.  If you have ideas that should be added to the list, please let me know…

 

1) Since forever, especially at home, it is my machine, I am master of it, and therefore I am a system administrator.  What a pain, logging off to install some software...  Well, I think I’ll bite the bullet and change my habits.  The hacker could never have stopped the antivirus software or done most of what was done if the machine were normally logged on as a user with little or no authority.  It is now time to protect my machine from myself and only log on with administrative authority when it really is necessary, as all security experts recommend.  This will be a hard habit to break.

 

2) Close ports that are not being used.  I stopped using VNC to access this machine, I should have uninstalled it.  At least I should have removed the port from the virtual server list in my NAT router.

 

3) On a regular basis, visit http://secunia.com/software_inspector/
This site has a Java based inspector that will look for signatures of application versions that are known to have vulnerabilities.  I discovered this when I googled “VNC vulnerability” to see if that could be how the hacker got in.  Google found the page pointed out at the top of this blog about this version of RealVNC, and I would have at least upgraded to a fixed version. 

 

4) Keep doing my drive image backups.  It is probably best to take the external drive off line following the backup, (assuming it is not needed for some other purpose) just to keep it safe from any hacking that does occur.  At least make sure the logged on user has only read access to it, and run the backup under another account.

 

I hope this never happens to you!