WSSWebServicePackager tool - Deploy Custom Web Services in Sharepoint
June 17, 2008 on 3:58 pm | In .NET Coding | No CommentsI had already slogged through the publishing of my own web services in Sharepoint a few times, as directed by The Horses Mouth. It’s not pretty, and it’s not fun. Takes about 20 minutes to half an hour, could be faster if you really know how to do it, I guess I’m just put off by all the careful quoting and whatnot.
Anyway, no matter what they tell you XML is not meant to be a human readable format! So it just so happens there is a tool that makes my life a whole bunch simpler. Without further ado, I’ll just give you the link. Go check it out. (It has a gui, so don’t worry about where the command line parameters reference is.)
NOTE: There is an OLDER version of this tool by another author on CodeProject — this is NOT that tool, this one is meant for WSS 3 (.net 2.0), the CodeProject one is for WSS 2 (.net 1.1).
It says that there is a requirement to place the file in the same directory as Disco.exe, so, using Visual Studio 2008 you can either copy the disco.exe from the Microsoft SDKs\Windows\v6.0A\bin to another folder where you put the WSSWebServicePackager.exe. OR you can just dump the WSSWebServicePackager.exe into the Microsoft SDKs\Windows\v6.0A\bin folder and it’ll be in your path automatically when you do a Visual Studio Command Prompt.
Make sure you save the files into the Layouts directory under your 12 hive (I mean specify the layouts directory when you’re running the tool as the output directory.) After you’re done with that you’ll have to copy them to the ISAPI directory, and edit the xml file so it can be discovered as if it were a regular old sharepoint web service. (This tool makes it so you don’t have to do all the steps in the first link I posted, but YOU STILL HAVE TO READ IT. There are some things that you won’t get except from that document, and unless you’re able to assume knowledge directly, well.. just go here and make sure you covered everything.
Soyo Topaz S - Hacking Native Widescreen Resolution on an Intel 945GM Express
May 10, 2008 on 12:31 am | In Uncategorized | 1 CommentThis evening started out disappointing, but here lies the key to a simple, relatively safe hack that helped me. I’ll start at the beginning…
I was so stoked today when my new 24″ monitor came in! A Soyo 24″ Widescreen 1920×1200! Nothing fancy of course, but it was a whopping $200 at geeks.com. First thing that happened was I plugged it in to the external monitor slot on my home laptop - a Dell XPS M1210.
It came right on, but hmmm… I couldn’t set anything but 1024×768 resolution! WTF!?!
I tried everything, tweaking the registry settings, hacking the inf file, installed PowerStrip… nothing worked.
I searched google one last time hoping to turn something up before I was going to just return the damned thing. Lo and behold I stumbled on this:
http://www.ryosa.com/widescreendrivers.html
That link explains how to use the Intel Embedded driver development kit to create custom drivers. I know it sounds daunting, but really, it’s simple. They have a wizard for the whole thing.
A quick run through the instructions at the above link, and I had it all working. I also used the linux documentation project to find the Modeline for the monitor, which is a good key to use to figure out what the timers should be. In case you happen to be using this exact same Soyo Topaz S 1920 x 1200 on an Intel 945GM Express chipset, then you’ll want the following settings:
linux kids can just copy this line directly:
Modeline “1920×1200@SOYO” 154 1920 1968 2000 2080 1200 1203 1209 1235 -HSync +Vsync
The rest have to use it to find these other settings:
154000 - Pixel Clock in Khz
1920 - Horizontal Active Area
1968 - Start of the Sync Pulse
2000 - End of the Sync Pulse
2080 - End of the Blanking Interval
Horizontal Sync Offset = 1968 - 1920 = 48
Horizontal Sync Pulse Width = 2000 - 1968 = 32
Horizontal Blank Width = 2080 - 1920 = 160
1200 - Vertical Active Area
1203 - Start of the Sync Pulse
1209 - End of the Sync Pulse
1235 - End of the Blanking Interval
Vertical Sync Offset = 1203 - 1200 = 3
Vertical Sync Pulse Width = 1209 - 1203 = 6
Vertical Blank Width = 1235 - 1200 = 35
I’d have really liked to have found that somewhere before digging around. Thanks to the modeline on tldp, it worked on the FIRST TRY of this trick because I had the right numbers. It’s beautiful, and I’m happy! YAY! Hopefully this helps at least one other person out of a jam. I’m just contributing to the massive store of knowledge google can bring to you and your kin by posting this. Feel free to ignore it if has nothing to do with you, your laptop, or your monitor.
Context-Aware SharePoint Designer Custom Workflow Activities
May 7, 2008 on 4:11 pm | In .NET Coding | 2 CommentsI had this nice little idea that I could teach the guys in my department how to do workflow with the Sharepoint designer so I wouldn’t have to do all that myself with the big Visual Studio Guns. All was going well until they needed to send out an email containing the URL of the site from which we were sending it. Not a link to an item in the site, the actual URL of the site itself.
“Simple!,” said I. I’ll just get it from the sharepoint object model with a custom activity. I wrote it all up, tried to use SPContext.Current.Web… and got it to puke nicely on a Null reference to Current. Of course! Why would a workflow activity have any reference at all to sharepoint? Technically a workflow activity doesn’t care where it’s hosted. But mine were to be hosted in Sharepoint, and that’s what I wanted to access. So, I looked around on the web and found nothing. I knew it had to be possible to get the context somehow, because other Sharepoint Designer Activities that came in-the-box were using it… so I looked for a clue.
I cracked open Microsoft.SharePoint.WorkflowActions.dll in Lutz Roeder’s Reflector, and lo-and behold there is a very cheap trick at work here!
Microsoft has implemented a custom dependency property by the name of __Context that is picked up as a Microsoft.SharePoint.WorkflowActions.WorkflowContext object IF it exists in your code. If you don’t implement such a property then it’s just not there, and nobody’s the wiser. This WorkflowContext object has a reference to .Site and .Web as properties, so it’s really handy to have at from within your custom activities that need to know where they are.
I’d like to post the code I found directly, but I can’t since it’s not mine. I will show you, however, what my code looks like.
public static System.Workflow.ComponentModel.DependencyProperty __ContextProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(FooActivity));
[Description("Context")]
[ValidationOption(ValidationOption.Required)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Microsoft.SharePoint.WorkflowActions.WorkflowContext __Context
{
get
{
return ((Microsoft.SharePoint.WorkflowActions.WorkflowContext)base.GetValue(FooActivity.__ContextProperty));
}
set
{
base.SetValue(FooActivity.__ContextProperty, value);
}
}
That’s a lot of typing if you write a bunch of these activities, so I made a codesnippet just for all of you out there to have and keep forever so you don’t have to do this. (Warning, do not just make this into a base class and derive your activities from it. It will throw an exception when you try to use it. I’m not sure why, but it does. You have to add this to every single activity you create for SPD that needs to know the sharepoint context.)
Here’s the code snippet I made:
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>spwfactivity</Title>
<Shortcut>spwfactivity</Shortcut>
<Description>Code snippet for creating a Sharepoint-Aware Workflow Activity</Description>
<Author>Dolan</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>classname</ID>
<ToolTip>Class Name</ToolTip>
<Default>Activity1</Default>
</Literal>
</Declarations>
<Code Language="csharp"><![CDATA[public partial class $classname$: System.Workflow.ComponentModel.Activity
{
public static System.Workflow.ComponentModel.DependencyProperty __ContextProperty =
System.Workflow.ComponentModel.DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof($classname$));
[Description("Context")]
[ValidationOption(ValidationOption.Required)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public Microsoft.SharePoint.WorkflowActions.WorkflowContext __Context
{
get
{
return ((Microsoft.SharePoint.WorkflowActions.WorkflowContext)base.GetValue($classname$.__ContextProperty));
}
set
{
base.SetValue($classname$.__ContextProperty, value);
}
}
public $classname$()
{
InitializeComponent();
}
}]]>
You’ll also have to add a Parameter value to the .actions file with your activity that specifies the __Context property as an Input property.
.
.
.
<Parameters>
<Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In"/>
.
.
.
</Parameters>
This one took me a while to figure out, but finally it worked!
If you want some more info on adding your own actions to designer (my article has thus far assumed you’re familiar with the process,) check out this link.
Update: I forgot to mention that just about the DAY after I figured this out on my own, I stumbled onto this codeproject article that dealt with this exact topic.
Just for fun I’ve also attached the snippet file so you don’t have to copy and paste it. Just save it into “%ProgramFiles%\Microsoft Visual Studio 9.0\VC#\Snippets\1033\Visual C#.”
VBScript to Remap your Outlook Profiles to a new server.
April 16, 2008 on 1:45 pm | In General Programming | 4 CommentsRecently recovered from an incident involving the slow and painful death of a MS Exchange Server. Right smack in the middle of the day, with some 800 mailboxes on that one host. We restored the mail stores to another Exchange Server, and ran a hack script to go and correct the homeMDB, homeMTA, and msExchMailServer attributes in the AD to point to the new host. That was the easy part. Then we had all these users with outlook profiles pointing to a dead server. Outlook may be resilient in picking the right server when you point it to the wrong server, but if the wrong server (to which is is pointed) is not available - as in if the server it’s pointed at is DEAD, then it doesn’t know to get the new info from the AD to point you to the correct one. This, of course, is exactly what happened to me an my ilk. We had some hundreds of users without profiles pointing to the right host. You’ve heard of Autoconfig for Outlook 2007, but that only works for NEW profiles, not existing ones suddenly pointing to a dead host. So what to do? Manually have all the users repoint their profiles by talking them through the Mail Control Panel widgets? NO! That’s expensive. Instead, write a script and deploy it as a login script.
Why a Login script? Well, because this script affects the HKEY_CURRENT_USER registry hive which only exists for a particular user when that user is logged on. At least for all intents and purposes that’s true. I think it may be possible to somehow enumerate all users on the HKEY_USERS hive, but I didn’t go that far. I apologize up front for not going the extra mile on this one, but hey, look! A free script.
NOTE: If you copy and paste it, and get a compile error, check for abberant the new-line characters caused by the squishing of my code by the text rendering on the page.
'------------------------------–
'Script RepointProfile.vbs
'Author: Dave Dolan
'Purpose: Repoints exchange profiles to use NewServer instead of OldServer
'------------------------------–
'(Editable Constants) Change OldServer and NewServer below as appropirate for the task
'----------------------------
CONST OldServer = "OldMailHostName"
CONST NewServer = "NewMailHostName"
'----------------------------
' Command Line Usage:
'------------------–
' RepointProfile.vbs [/print:true|false]
' -- (optional) print parameter when set to 'true' displays what it's doing, otherwise it prints nothing
' ---------------------------------------------------------–
' NOTE: VERY IMPORTANT: Run this in the context of the current user to change the profile settings,
' since it affects HKEY_CURRENT_USER!
'----------------------------------------------------------------------
'--------- Edit NOTHING Below this line ----------------------
'if they have non-exchange profiles, they're gonna throw (harmless if skipped) errors. I care not.
on error resume next
CONST NetBiosValue = "001e6602"
CONST FQDNValue = "001e6608"
CONST xFiveHundredValue = "001e6612"
Const HKEY_CURRENT_USER = &H80000001
printParam = Wscript.Arguments.Named("print")
if len(printParam) >= 0 then
if ucase(printParam) = "TRUE" then
printValues = 1
else
printValues = 0
end if
else
printValues = 0
end if
computerName = "."
const BASE_KEY = "Software\Microsoft\Windows NT\CurrentVersion\Windows Messaging Subsystem\Profiles"
set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & computerName & "\root\default:StdRegProv")
objReg.EnumKey HKEY_CURRENT_USER, BASE_KEY, arrSubKeys
for each subkey in arrSubKeys
if printValues = 1 then
Wscript.Echo "Subkey = " & subkey
end if
subKeyPath = BASE_KEY & "\" & subkey & "\" & "13dbb0c8aa05101a9bb000aa002fc45a"
objReg.GetStringValue HKEY_CURRENT_USER, subKeyPath, NetBiosValue, nbServerName
objReg.GetStringValue HKEY_CURRENT_USER, subKeyPath, FQDNValue, fqdn
objReg.GetStringValue HKEY_CURRENT_USER, subKeyPath, xFiveHundredValue, X500
fqdn = ucase(fqdn)
if printValues = 1 then
Wscript.Echo "Current Values"
Wscript.Echo "------------–"
Wscript.Echo "Netbios Value: " & nbServerName
Wscript.Echo "FQDN Value: " & lcase(fqdn)
Wscript.Echo "X500 Value: " & X500
end if
if instr(nbServerName, OldServer) then
nbServerName = Replace(ucase(nbServerName), OldServer, NewServer)
fqdn = lcase(Replace(fqdn, OldServer, NewServer))
x500 = Replace(X500, OldServer, NewServer)
objReg.SetStringValue HKEY_CURRENT_USER, subKeyPath, NetBiosValue, nbServerName
objReg.SetStringValue HKEY_CURRENT_USER, subKeyPath, FQDNValue, fqdn
objReg.SetStringValue HKEY_CURRENT_USER, subKeyPath, xFiveHundredValue, X500
if printValues = 1 then
Wscript.Echo ""
Wscript.Echo "New Values"
Wscript.Echo "------------–"
Wscript.Echo "Netbios Value: " & nbServerName
Wscript.Echo "FQDN Value: " & fqdn
Wscript.Echo "X500 Value: " & X500
end if
end if
next
set objReg = nothing
Visual Studio 2008 Workflow designer BUG!! (feature?)
April 7, 2008 on 11:53 am | In .NET Coding | No CommentsI just got back from tearing my hair out over a frustrating bug I found in the workflow designer included with Visual Studio 2008. First let me start by saying that developing using sharepoint as a platform for workflow, especially with integration into Visual studio has been an overall pleasant experience. I have been able to work at this much faster and easier in 2008 than I ever had using the workflow extensions for VS 2005. Of course, sharepoint is my focus for a workflow host, so I’m happy with the options I have out of the box. That won’t be the case for many who use workflow for other, non-sharepointy things. You’ll have to wait for the rumored and afamed 2008 version of the extensions to be released in June of this year.
Now, about this bug. As you may or may not be aware, workflow serializes it’s state to a persistence provider when it’s ‘put to sleep.’ This state is basically saved a as state bag (hashtable) of data and pumped as a binary lump to a persistence provider. Each property of each item is known by a key consiting of, among other things, its property name. Now, since multiple activities, or even state variables, can possibly contain properties of the same name, it makes sense to add something else to the mix to identify one as being unique from the other. You might think they’d use some kind of a guid or something, and internally that’s involved somehow, however, there is a different, seemingly more accessible way that workflow foundation solves this problem. Activities that require continuations based on the serialization also require that you specify what’s known as a Correlation Token. This is a pairing of an arbitrary string with an owner activity. Event driven activities, for one example, that wish to consume sequential or related events will need to use the same Corellation Token if they are to act upon the same item. The example that I’m using (and so happens that I was cursing) is the CreateTask to OnTaskCreated pairing. If you want to handle the OnTaskCreated event for a particular CreateTask activity you have to make sure that you’re using the same Correlation token.
Easy enough right? The designer lets you, via the property panel, enter the name of the token, and select the owning activity. That’s fine, of course, unless you start getting to antzy about the order or layout of your activities and you cut one here and paste it there. After you’ve copy/pasted one to re-arrange it, you’ll notice upon inspection of the property grid that all seems to be intact. The correlation token is the same as it was, specifying the same name of the token, as well as the identical owner activity. When I run the workflow after doing this, I discoved something quite strange.
The OnTaskCreated handler wasn’t firing until the next one was created.
After much pain and suffering, and a support call to microsoft, which I paid for, but as of yet have got no response to it, I discovered something in the designer code that explained my problem. (This code appears in the [workflowname].designer.cs file, in the InitializeComponent method’s implementation block.)
The tokens look the same, as in they have the same attributes, but they are two separate instances of the CorrelationToken class. This is probably something that the designer overlooks, because it’s simply creating objects with the values to fulfill the properties I’ve set, instead of backtracking to see if some token or other is already there from before. So I corrected the assignment statements to use the same tokens for both instances, and it’s all better now.
see here:
correlationtoken1.Name = "someStateTaskToken";
correlationtoken1.OwnerActivityName = "someStateActivity";
this.SendDirRejectionNotice.CorrelationToken = correlationtoken1;
...
correlationtoken2.Name = "someStateTaskToken";
correlationtoken2.OwnerActivityName = "someStateActivity";
this.SendDirApprovalRequired.CorrelationToken = correlationtoken2;
should become this:
correlationtoken1.Name = "someStateTaskToken";
correlationtoken1.OwnerActivityName = "someStateActivity";
this.SendDirRejectionNotice.CorrelationToken = correlationtoken1;
...
this.SendDirApprovalRequired.CorrelationToken = correlationtoken1;
I just looked through the rest of the deisgner generated code for the same sort of constructs to make sure that I had no dups. Phew, what a train wreck! I had to correct it in about 7 places.
So, all things considered the experience I’ve had with the workflow and designer has been ok, but this is a glaring hole. You want to hear my theory as to why this happens, and why the event actually fires after the next task is created?
Sure, I’ll tell you. Since the idea of the tokens is to provide a handle on state before and after serialization, it’s probably referenced by it’s values after it’s deserialized, (i.e. when the code tries to hydrate the instance of the workflow, it pairs the tokens with their owners by the names of the instances.) This means that if you always persisted it, and re-hydrated it before the event fires, the duplicate token declaration ‘in code’ probably wouldn’t matter, because it would be ‘reconnecting them’ by their names. But the problem I experienced is becasue the first and second instances of the tokens are both instantiated right after my workflow starts, and they aren’t serialized yet, and this reconnection doesn’t happen yet… and somewhere inside the workflow’s in-the-box code these tokens are compared by reference or some other non-value hash for equality, instead of by value of their members, and of course, they don’t match that way, they’re separate instances!
I don’t know if fixing it like this is A) stable (in that it will survive any change I make in the designer), B) a good idea, which it probably isn’t. It’s a hack to fix a broken workflow for this one very specific issue, and I’m hoping to heck there is a hotfix for it. I wouldn’t recommend it beyond a build cycle or two. I don’t know when this code is regenerated by the designer, nor what causes it to create separate token instances (I do know that copy/paste is one!). I’ll post back if I find out.
I would classify that as a bug. Good luck folks! Love that workflow!
I have a story to tell you. (Non-technical)
March 22, 2008 on 12:04 am | In Uncategorized | No CommentsI know this isn’t par for a programmer’s course, but oh well. This started off as an email I sent my brother, and I’ve added a bit and well, here it is.
The other day I went for a run in Downtown Tampa. I intended to be out for, oh, like 30 - 40 minutes. I ran up and down small streets ending up in some huge (and by huge I mean it was for at least a mile in each cardinal direction) upscale residential neighborhood where there was a Hummer and a Beamer in every driveway and a Mercedes in the garage. The property was all beach front vista. Actually, it was ‘bay front’ and the difference between the two was very obvious to me… it stunk like rotten sewage in the whole neighborhood. These people paid millions of dollars to live in a so-called upscale neighborhood that smells like a trash heap. I laughed to myself about the kinds of life-pressures that push one to do such a thing. I knew it wasn’t just that night that it smelled like that, because I’ve been in the general area before a few times, and it always had, I just never really thought about it all that hard. Well, I had been gone about 40 minutes at this point and it was starting to get dark. I realized that I was totally lost, and to my surprise I found that I had been going south after I thought I had turned around going back north and that for the entire 40 minutes I had been running further from my hotel. So I turned back around, my lungs burning, thinking to myself that I might as well stop and walk, start to panic and find my way back as fast as possible. Then I did actually stop, just for a minute. I looked around, and noticed that I was surrounded by palm trees, and that the air was 80 degrees. The stars were sparkling clear, and the moon was almost full. I was in a tiny little stinky paradise, while my co-workers were at home setting their alarm clocks to get up the next day and troggle off to work. My veins were bursting with my heartbeat, and I couldn’t quite see straight because of the oxygen debt. I was smiling to myself as I took off my shirt, and picked up at full speed back north. I was thinking, normally, I’d be upset. I’d be trying to hock some device I had on me to grab a taxi, or avoid the dark alleys so I wouldn’t have to worry if this were the right way to go or not, how long would it take me? How far off course was I? But in this instant, I realized I was living a moment that I wouldn’t have the opportunity to ever live again, and even the experience of the burning in my lungs was something I wouldn’t trade for the world at that moment. I was ecstatic, and I pushed myself harder than I’ve ever done before to run all the way back. Through the sprinklers that people had on for their lawns. Past the folks cruising by in brightly polished Miata’s and perfectly plated Benz’s wondering “Who’s the idiot running in the dark, while I’m in this fancy car? Must be a loser.” All the while I knew that I really had the upper hand, I didn’t have to worry about any of it. And I don’t live in a neighborhood that smells like a sewer.
It was a good night. And boy was I sore the next day.
Seriously, quit bashing Microsoft for being successful.
March 14, 2008 on 11:58 pm | In Uncategorized | 1 CommentBefore I begin, I’d like to point out that I like open source. I use it and I contribute to it. I think the educational value, and the practicality of it in lots of situations warrants its existence, as we can see because it still exists. I relish the fact that both open source is here and helps me to learn and diffuse essential knowledge, and yet there is still a thriving market for proprietary software that makes ones skills profitable. But the bashing of software for profit, it’s senseless. I can’t stand it any more. What is the whole idea here? I’m a regular reader of Slashdot.org, an occasional reader of Digg.com, and various other news sites, and I’ve come across such an endless stream of anti-Microsoft and closed minded jealous raging rants against large companies that I just can’t stay silent on the issue any more. It makes my blood boil. I have so little respect for the ignorance of folks who can’t see their nose in front of their own green clouded eyeballs that I’m going to do some ranting of my own. Are these people really seeking the destruction of our economy? When did profit become a dirty word?
I’ll start with the obvious. What is the point of a for profit corporation? A for profit corporation is an entity which exists to make money. That’s why they call them “For-Profit.” It’s very subtle I know, but if you can’t fathom that, bear with me. I have heard it said that the government only allows for the establishment of such entities as corporations so that the public interest is served. This is true. However, this service of the public good isn’t what one might expect at first. I’d venture that the average American imagines that the public good is best served by creating a company that doles out employment and benefits, and that’s the best way to serve the public good. It isn’t. The best way for a business to serve the public good is to drag as much money from outside the economy into it. Wherever you put it, be it in the pockets of the higher ups, in the concrete that the buildings are built on, in the shops surrounding the offices, in the gas tanks of the employees as they drive to work. You can put it in the supply chain, in the pockets of the ISPs that host the traffic for their enormous websites, in the hands of the developers who use their platforms to generate their own Independent Software Vendors (ISVs) and sell their own minor empires worth of software halfway across the country or indeed the world. Stash away cash in the refrigerators of the caterers who bring in executive lunches, or the company that handles the accounting and payroll transfer. Give it to the advertisers who make money on the fact that there is a reputable publication carried on the shoulders of giant companies, whose every word is read by scores of thousands of people all across the globe, and as a result of this exposure now have the opportunity to benefit the public good themselves. This giant corporation has given them a forum for their own little voice to be heard. In pursuing its own self-interests, the coattails of a large corporation become very long, and allow for countless other entities to hitch a ride around the entire globe on them. What the hell is wrong with that?
If you’re a tiny little ISV trying to start up your own business, it’s up to you to pick a good and viable business model that suits your target industry and market space well. If you’re attempting to fill a need that has already been filled by a dominant force and you do not have the clever product or wear-with-all, or business structure to support a takeover of that industry space, then you’re the one making bad decisions. You don’t have the ‘right’ to be successful, you have the right to try. If you can’t push the leader off his pedestal then you have chosen the wrong field. If you can’t establish a sufficient specialty niche for yourself, your business model is wrong. Equal opportunity is not the same as equal results. More generally, fairness and justice are two totally different things. Justice is a right which should be enforced, but fairness is not. It is just for the best product or marketing to prevail in an open competition scenario. It is not fair that it’s tough for a little guy to break in. Ultimately, and over time, the results become more pronounced than in any one decade or small years span — the customers vote for the winner with their dollars. The fact that a person decides they should be able to compete in the web browser market, for example, does not mean that he should automatically inherit an equal slice of the market share just for having laid a public claim to it. In the case of Firefox, for example, they give away the product for free, and still, they have a smaller market share. Does that mean that some government somewhere should come in now and mandate that X% of all people in the world now need to use Firefox? No, that’s silly, and we all know it is. IF Firefox really fills a glaring need that cannot be so filled by Internet Explorer, then it will be taken up by the section of the market that has this need. People aren’t the idiots that some would have you would believe they are. Users and developers of software don’t choose Internet Explorer because they ‘want evil to win.’ They do it because it’s more practical for whatever situation they are in. This practicality comes from two factors, one: they don’t know about the other one, and don’t see a need to look for a new solution to a problem they’ve solved, and two: perhaps there is some feature of IE, however ill-advised it may be to use it, in whatever situation that they perceive as being necessary (this might include Microsoft investment in their company.) That perception is theirs to have. It isn’t some governments to give or demand. Eventually even super-dominant industries fade and fail giving way to new and better ones. Sometimes large companies survive the evolution of disruptive technologies, sometimes they don’t. Nobody makes horse and buggey whips anymore. Should that have been protected on the grounds that it might not have been fair to let the auto makers have their run of the economy? It’s the way of the world, and the truth is that it works. Look at where we are now. We got here because it works. It’s not nice in some small, short term, slice of life views, where large swaths of workers are laid off or have to take pay cuts, but eventually these things correct themselves. Whole towns spring up and die around industries and it’s always been that way. Walmart and Microsoft didn’t invent the idea of inequity. Inequity is the driving force behind progress. It’s the inspiration for ambition. It drives those who have the will and the knowledge, and especially those with the will to develop the knowledge, to do ever better and be steadily more useful and more productive. It forces those who are on the losing side, who will not give up, to try harder to get on the winning side. In the process, the stuff you can find on the shelves at the super market grows in variety, and drops in prices.
If one company abuses its position of power and doesn’t put the needs of the customers first, they will eventually suffer the consequences. If Microsoft would gouge the IT industry because they believe they have a position of infallible dominance, they will find that one by one, year by year, enterprise agreement by enterprise agreement, they will lose their market share. If they don’t adjust to the new situation, eventually they too will fall off the map. In serving the needs of its customers, a large company serves its own interests. The customers of a super corporation are not just the folks who live in the neighborhood. They are the collateral benefactors of all of the industries that go into supporting that mega entity, and are supported BY the mega entity, and they can live anywhere in the world. Tell me now that this isn’t to be considered the good of the public.
Are the haters of large corporations to say that it is not good for a company to make money? Or maybe just not large amounts of it? Probably they’d say it’s the second one, but they’re forgetting the fact that for a large company to just exist on planet earth for a single day, they have to spend a lot of this money on other folks, like their employees, for one. They have to pay the bills, they have to hire advertisers, so ultimately it’s the mega-sized companies that bring you Frasier, Survivor, Oprah, and even (shudder) Lou Dobbs Tonight.
My ultimate beef though is not a practical one. It’s an idealogical one. We should encourage those who succeed to lead as examples for others so that they can see that success is something that’s worth pursuing. The more successful people and companies we have in this country (or any country,) the more successful the economy at large will be, and the higher the standard of living we’ll have. And individually, it’s rewarding to see your ideas through to production, and moreso on a mega-scale. Bill Gates has earned the right not to comb his hair on TV, and I’ll bet that even Brooke Shields would like the same right. The cowering masses of admirers aren’t what the real winners seek. They’re a side effect of doing something that nobody else has done, and doing it exceedingly and emphatically well. Everyone admires Bill Gates, whether or not they’ll admit it. He’s a man of action, a man of success, and for some, the picture of what they can not aspire to be. They think that because they can never become like him that they should instead try to seize some of that which he has created (as in with lobbyists or legislation.) To slice off a chunk for those who will never do the things he has done, and will not lift a finger to that end. That’s where they’re wrong. You can aspire to be as great as you like. You can pursue your path to the end of your days. Nobody is going to give it to you, and they shouldn’t. It’s the ‘hard’ part that makes it so great. If you don’t make it to be as successful as you had aimed by the time you die, you won’t be walking around cursing the fact. But at the risk of sounding like I’m making a bad pun, (or worse, a pro basketball coach,) “You’ve gotta play to win.”
Tired of the Crappy MS Oracle OLDEB Provider?
February 27, 2008 on 11:43 am | In .NET Coding | No CommentsIf you use Linked servers in SQL Server 2005 to connect to oracle servers, and have been frustrated by the slowness of the Microsoft OLEDB provider for Oracle, then we have something in common.
Lucky for you and me, there is a fix.
Step 1: Install the Oracle Client freely downloadable from their website on your SQL server host. (Requires a little spam info.)
Step 2: Configure your client by setting up your TNSNames.ora file as per usual.
Step 3: in Management studio, login as a server admin (sa, or someone with the server admin role)
Step 5: Issue the following commands, (it’s in secret code, so be careful!)
exec sp_addlinkedserver 'linkname', 'Oracle', 'OraOLEDB.Oracle', 'oraclehostname'
exec sp_addlinkedsrvlogin 'linkname', false, null, 'usernamehere','secretpassword'
That’s it kids! Just say no to the wizard.
You can then create a view in one of your existing databases that selects from this Link, and almost as magically every tool that hits SQL server can now be using SQL Server as a conduit for Oracle. (It’s better to do this if you’re combining data or something, not just as a very expensive DB provider of course, but it still works however you like it, and the chances are you’ve got another SQL host somewhere that wouldn’t mind pulling some data for your developers convenience.) My FAVORITE feature about doing this is that I can now do LINQ to Oracle. So there! Go Forth, Be Multiply, and Fruitful.
A Picture of The Competition
February 6, 2008 on 12:14 am | In Uncategorized | 2 CommentsA good friend of mine went to India recently. I’ll let his commentary and the picture he brought back with him speak for itself.
“While in India recently I visited a temple in a town called Kalahasthi in Andhra Pradesh. This photo was taken around 7:00pm under heavy street lights (see the lights in the stores it was night time). This girl was studying on the divider surrounded by heavy traffic….of course this photo does not fully show the traffic, but Uma (my friend who took the picture) had to wait a few minutes and got a clear shot only after taking 5-6 pictures. As you can see the vehicles are moving and there was a lot of truck traffic as well……the girl was really oblivious to all the humdrum surrounding her, she was just doing what a student was supposed to be doing on a school night. When the power is out at homes or when there is no power at homes at all, studying under street lights is a very common scenario.”
“We have a video that shows the street light and all that, but anyway it is a very powerful picture showing the face of the competition.”
photo by Uma Shankar
Quick, list the dbs and Users!
January 21, 2008 on 2:21 pm | In SQL Code | No CommentsI’ve been orchestrating a move from an old SQL 2000 database to a SQL 2k5 DB host. Most of the dbs are in use somewhere by some application or other, and I can’t tell by looking at it just what they are. One of the things I’ll need to do is contact all of the users of each one and ask them to tell me what the impact is, as well as inform them that they’ll need to swap a hostname out in the connection string. No problem, I can just click through all 50 databases on the host and look at all the users, and write them down, and send an email to them all asking what gives… The trouble is, half the time they have no idea what db’s are on the host, and what if any they have to do with it. I didn’t feel like spending about 4 hours on this, so I quickly tossed off a script that generates some SQL to figure out the real list, without getting too complicated here. In case you find it useful, here’s the script to generate the second script:
use master
-- below is a query to generate a single query to get all the users for each database
begin
declare dbs cursor for select name from sysdatabases
declare @dbName VARCHAR(25)
open dbs
fetch dbs into @dbName
while @@fetch_status >= 0
begin
if @dbName in ('master', 'msdb', 'tempdb', 'pubs', 'model')
begin
print '-- skipping system db ' + @dbName
end
else
begin
print '----------------------------------'
print '-- ' + @dbName + ' --'
print '-------------------------------------------------------------------'
print 'select ''' + @dbName + ''' as [DB], name as [User] from ' + @dbName + '.dbo.sysusers where hasdbaccess = 1'
print 'union'
end
fetch next from dbs into @dbName
end
close dbs
deallocate dbs
end
go
After that runs it will generate in the output window (or the console if you use OSQL or some other command line tool to run it,) this form of output. I pipe it to another file, and change the last ‘union’ to a ‘go’ and we’re done. I probably should have also excluded the user dbo, but I didn’t you can if you want.
----------------------------------
-- FirstDB --
-------------------------------------------------------------------
select 'FirstDB' as [DB], name as [User] from FirstDB.dbo.sysusers where hasdbaccess = 1
union
----------------------------------
-- aspnetdb --
-------------------------------------------------------------------
select 'aspnetdb' as [DB], name as [User] from aspnetdb.dbo.sysusers where hasdbaccess = 1
union
----------------------------------
-- OtherDB--
-------------------------------------------------------------------
select 'OtherDB' as [DB], name as [User] from OtherDB.dbo.sysusers where hasdbaccess = 1
go -- changed from union as generated by the script
-- this continues until all dbs are enumerated, excludes the system dbs.
Powered by WordPress with Pool theme design by Borja Fernandez.
Entries and comments feeds.
Valid XHTML and CSS. ^Top^

