I've been working remotely, doing primarily development and architecture work, for the past 24 months. During this time I've used quite a few different communication mediums, each of which had their strengths and weaknesses.
Emails are the primary way of communicating. They are great for keeping track of what was said, clearly thinking out and stating a point, and useful for managing work.
Instant Messaging (IM) is very useful for a quick back and forth discussion: "how do you do X?", "can I checkout Y?", " I can't access Z, is it down?" Again, you have a full searchable history of what's been said which is very useful. If you find yourself chatting for more than 30 mins then you should probably have made a phone call. You also need to be careful not to slip into idle chatting which can be counter-productive (for both parties!). You can however, answer in your own time and you can flag yourself as busy if you don't want to be disturbed. Also, Skype client offers encryption which keeps everything safe.
Voice/Skype Sometimes a 3-day email back and forth could be easily solved by a 10 minute phone call, particularly something like talking though a business requirement with a BA. And it is good in the remote development world, to have a regular voice conference call/team catch-up. I used Skype because it is free, and free is good!
Collaborated Documents I have started using this with my "To Do" spreadsheet via Google Docs. It is not yet proving super-beneficial but I think that over time, once we adjust to think this way, it will offer a lot and save a lot of to-ing and fro-ing of document versions. I've used collaborated docs to good effect with bug lists.
Wikis These are super-useful. Typically have one per project. Source control, all project documentation, bug lists, project "how-tos" etc. People end up using it because they are just so darned easy to update! All those 1/2 to 2 pages documents end up being written in here. If your team are slack at documenting then try introducing a wiki! My only gripe (as a team member) is that it is not so easy to throw it on a flash drive and take it away with you when you leave.
Twitter Played with this for status updates but it didn't stick.
Monday, March 3, 2008
Thursday, February 28, 2008
Can't find your .Net dll in the VB6 Project References list?
I had created a new .Net Dll and done everything right, but couldn't for the life of me find the DLL in the VB6 references list. Everything looked fine in the registry with the HKEY_ROOT/CLSID and HKEY_ROOT/TYPELIB stuff there OK with the right Guids etc.
Normally you find it in the References list under the dll name eg. MyDll.dll would be called "MyDll" in the list. BUT, if you put a description in the .Net project file (Properties-Application-Assembly Information, the "Description" box), then that is the name that will appear in the References list, and also the name that will we shown under the Type Library list in the OLE View tool.
Moral of the story? Don't use the .Net Assembly Description field for COM compatible DLLs! Damn, that cost me hours!
Normally you find it in the References list under the dll name eg. MyDll.dll would be called "MyDll" in the list. BUT, if you put a description in the .Net project file (Properties-Application-Assembly Information, the "Description" box), then that is the name that will appear in the References list, and also the name that will we shown under the Type Library list in the OLE View tool.
Moral of the story? Don't use the .Net Assembly Description field for COM compatible DLLs! Damn, that cost me hours!
Wednesday, February 27, 2008
Moving your svn repository to a Parallels Shared Network Drive on the Mac
I'm running svn under windows as a Windows Service on my Parallels virtual machine (not using Apache). I wanted to move the repository from my local c:\ drive to a shared Parallels folder to take advantage of TimeMachine backups of my svn repository. I ended up deleting and recreating the SVN service. These are the steps:
1. Find the service name. Look in the services console. Find the display name of the service in there. Then, from the command prompt, use the "sc query" command to list all of the services and find the matching display name.
2. Check the current config, especially the binary path to the snvserve exe.
3. Delete the service.
4. Create the new service with the new file system path (don't forget the spaces after the '=' signs and the \ before the nested quotes). It is important to use the UNC path to the shared Parallels folder and not the drive letter, because the drive letter will not work! I found the UNC path by clicking "Map Network Drive" under explorer and looking in the drive dropdown. A quick test of "dir \\.psf\osxpshared" will tell if you got it right.
sc create svnrepos binpath= "\"c:\program files\subversion\bin\svnserve.exe\" --service -r \"\\.psf\osxpshared\svn\"" displayname= "Subversion Repository" depend= Tcpip start= auto
If you get the mysterious "service is marked for deletion" message then make sure you have closed the services console. This can keep a handle to the old service and stop it from being deleted.
5. Start the new service.
6. Check it works.
1. Find the service name. Look in the services console. Find the display name of the service in there. Then, from the command prompt, use the "sc query" command to list all of the services and find the matching display name.
2. Check the current config, especially the binary path to the snvserve exe.
C:\Documents and Settings\Administrator>sc query svnrepos
SERVICE_NAME: svnrepos
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
C:\Documents and Settings\Administrator>sc qc svnrepos
[SC] GetServiceConfig SUCCESS
SERVICE_NAME: svnrepos
TYPE : 10 WIN32_OWN_PROCESS
START_TYPE : 2 AUTO_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : "C:\program files\subversion\bin\svnserve.exe" --service -r "c:\svn"
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : Subversion Repository Local
DEPENDENCIES : Tcpip
SERVICE_START_NAME : LocalSystem
3. Delete the service.
sc stop svnrepos
sc delete svnrepos
4. Create the new service with the new file system path (don't forget the spaces after the '=' signs and the \ before the nested quotes). It is important to use the UNC path to the shared Parallels folder and not the drive letter, because the drive letter will not work! I found the UNC path by clicking "Map Network Drive" under explorer and looking in the drive dropdown. A quick test of "dir \\.psf\osxpshared" will tell if you got it right.
sc create svnrepos binpath= "\"c:\program files\subversion\bin\svnserve.exe\" --service -r \"\\.psf\osxpshared\svn\"" displayname= "Subversion Repository" depend= Tcpip start= auto
If you get the mysterious "service is marked for deletion" message then make sure you have closed the services console. This can keep a handle to the old service and stop it from being deleted.
5. Start the new service.
net start svnrepos
6. Check it works.
svn info svn://localhost
Thursday, February 21, 2008
How much can you change your WSDL before you need to recompile your .Net consumer?
If you have a .Net application that is consuming a web service, via a web reference, how much does the WSDL have to change before your compiled application will break? I set up a simple .Net web service and tried the following:
Then I tried nested objects as parameters (we use these a bit):
So a web service call is pretty forgiving. We can change most of it without a recompilation being required.
- Added a new method. OK
- Removed a method (not the one we are calling). OK.
- Modified the method by changing the argument name. Method call still worked but no data was passed in.
- Modified the method by adding an additional parameter. Method call still worked but new parameter was not set (obviously). Original parameter was still passed through.
- Modified the method by removing a parameter. Method call still worked!
- Modified the method changing the parameter type from string to int. Method FAILED with format error.
- Modified the method changing the return type from string to int. Method call still worked.
Then I tried nested objects as parameters (we use these a bit):
- Modified the method by changing the argument name of one of the nested objects parameters. Method call still worked but no data was passed in that parameter; all other params still populated.
- Modified the nested object by adding an additional parameter. Method call still worked but new parameter was not set (obviously). Original parameters still passed through.
- Modified the method by removing a parameter. Method call still worked!
So a web service call is pretty forgiving. We can change most of it without a recompilation being required.
Tuesday, February 19, 2008
.Net 2.0 and calling dynamic Web Services
It is really easy to use a web service in .Net 2.0. You just add a "Web Reference" to you project and point it to your WSDL URI. A proxy class is generated that provides you with methods that line up with the methods available from your web service.
OK, but I want this to be dynamic: I want to deploy this to my production environment which uses a different web service address, without recompiling it.
Easy, you just make sure that your web reference has the "dynamic" property set and an app.config will be added to your project. Take a look at it. Now you can change the access point via the app.config file. So you just deploy a different app.config file in production. If you are using DLLs and COM interop you can have a lot of fun trying to get the config files loading (see here). If needs be, you can roll your own config file and set the access point URL manually before invoking the web service via the ".URL" method on the web proxy.
OK, but I want this to be really dynamic: I don't know the WSDL at compile-time, all I know is the method signature; I want to provide the WSDL at run-time.
It starts to get a bit ugly now. But if you know the method signature, eg:
then you can define an interface class which you can use in your code at compile time. Then, at run-time, you can look up the WSDL, generate assembly source code from it, compile the assembly and have that assembly implement your interface. Google is your friend here. If found a few examples but this implementation of a WebServiceProxyFactory is pretty darned useful. Note that it does take time to build and compile this proxy assembly - you probably won't be wanting to do this every time, so you may have to implement some kind of proxy-caching.
Hmmm, OK, but I want this to be really, REALLY dynamic: I don't even know the method signature at design time - I want to examine the WSDL and work out which one to use.
Yeah right! Maybe you can get the user to write the code? But seriously, there are times when you might want to call a web service that hasn't even been designed yet - maybe you are deploying your app to a number of clients and allowing them to hook in their own web services calls? It is time to read your SOAP manual. You're going to have to grab the WSDL, interpret it, find the method you want to call, build a soap envelope with your values inserted in the right places, and make the web service call. A quick google of HttpWebRequest and SOAP should get you on the right track. This is no trivial task!
OK, but I want this to be dynamic: I want to deploy this to my production environment which uses a different web service address, without recompiling it.
Easy, you just make sure that your web reference has the "dynamic" property set and an app.config will be added to your project. Take a look at it. Now you can change the access point via the app.config file. So you just deploy a different app.config file in production. If you are using DLLs and COM interop you can have a lot of fun trying to get the config files loading (see here). If needs be, you can roll your own config file and set the access point URL manually before invoking the web service via the ".URL" method on the web proxy.
OK, but I want this to be really dynamic: I don't know the WSDL at compile-time, all I know is the method signature; I want to provide the WSDL at run-time.
It starts to get a bit ugly now. But if you know the method signature, eg:
public string HelloWorld(string inArg)
then you can define an interface class which you can use in your code at compile time. Then, at run-time, you can look up the WSDL, generate assembly source code from it, compile the assembly and have that assembly implement your interface. Google is your friend here. If found a few examples but this implementation of a WebServiceProxyFactory is pretty darned useful. Note that it does take time to build and compile this proxy assembly - you probably won't be wanting to do this every time, so you may have to implement some kind of proxy-caching.
Hmmm, OK, but I want this to be really, REALLY dynamic: I don't even know the method signature at design time - I want to examine the WSDL and work out which one to use.
Yeah right! Maybe you can get the user to write the code? But seriously, there are times when you might want to call a web service that hasn't even been designed yet - maybe you are deploying your app to a number of clients and allowing them to hook in their own web services calls? It is time to read your SOAP manual. You're going to have to grab the WSDL, interpret it, find the method you want to call, build a soap envelope with your values inserted in the right places, and make the web service call. A quick google of HttpWebRequest and SOAP should get you on the right track. This is no trivial task!
Wednesday, February 13, 2008
How to read an app.config setting for your DLL from your dll.config file
It turns out you can manually read the app.config settings for your DLL, using the ConfigurationManager.OpenMappedExeConfiguration. This is pretty darned ugly, but it works. It will look in the location of the currently executing assembly (ie. you dll's location) for the file "{dllname}.config". You still need to manually deploy the config file to this location - the setup package only deploys the EXE config file.
To get the code working, first add a reference to the .Net "ConfigurationManager" to your project, then add "using System.ConfigurationManager" to your class.
To get the code working, first add a reference to the .Net "ConfigurationManager" to your project, then add "using System.ConfigurationManager" to your class.
public string getOpenedConfigValue(string keyName)
{
string codebase =
System.Reflection.Assembly.GetExecutingAssembly().
CodeBase;
Uri p = new Uri(codebase);
string localPath = p.LocalPath;
string executingFilename =
System.IO.Path.
GetFileNameWithoutExtension(localPath);
string sectionGroupName = "applicationSettings";
string sectionName =
executingFilename + ".Properties.Settings";
string configName = localPath + ".config";
ExeConfigurationFileMap fileMap =
new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = configName;
Configuration config =
ConfigurationManager.OpenMappedExeConfiguration(
fileMap,ConfigurationUserLevel.None);
ConfigurationSectionGroup group =
config.GetSectionGroup(sectionGroupName);
ClientSettingsSection section =
(ClientSettingsSection)group.Sections[sectionName];
SettingElement elem = section.Settings.Get(keyName);
if (elem == null)
return "";
else
return elem.Value.ValueXml.InnerText.Trim();
}
App.config in C# with VS2005 - Part II: DLL within an EXE
In part I I looked at using the app.config from an EXE. In part II I'm going to look at using app.config from a DLL that is called by an EXE.
So, create a DLL project (mine is called "TestAppConfigDll") and add it to your EXE project. Use the Settings designer again to add your app.config file to your DLL (right-clicking on the project, selecting "properties" and then choosing the "settings" tab). I'm going to add an "Application" setting called "MyDllVal". Again we get a pretty similar looking app.config file in our project:
And again, we can access the value in code using:
No surprise to find that the config file in our bin folder (..\TestAppConfigDll\bin\Debug) is prefixed by the dll name, "TestAppConfigDll.dll.config" in my case. BUT looking in the bin for the EXE project (which references the dll and contains a copy of my dll file), there is no dll.config file, just the original exe.config. And the exe.config has no "MyDllVal" property. If I run the EXE it picks up the original value for "MyDllVal" but I have no way to modify it! It knows the original compile-time value because it has been hard-coded into the "Settings.Designer.cs" file that was generated when you entered your value via the Settings designer. Here is the code if you are interested (my original value was "18.2"):
So, what if I add a dll.config ("TestAppConfigDll.dll.config") under the EXE bin folder - will it read it on start-up? Nope - it doesn't read it.
So, maybe it is looking in the exe.config for my setting. What if I merge my "MyDllVal" setting into the exe.config file - will it read it on start-up? Wooeee! That works! So I had to take two chunks of xml from the dll.config to the exe.config; (i) the "section", and (ii) the "{dllname}.Properties.Settings". The resulting exe.config looks like this:
So the upshot is, if the DLL is called from an EXE, then the DLL will try to get its app.config settings from the EXE's app.config file. Even if I remove the EXE's app.config, the DLL does not use the DLL's app.config file.
Man, this is annoying! Why have they done it this way? Maybe it is so that shared DLLs in the GAC can have different config settings for different EXEs. But even then, couldn't they have used the EXE config settings first, and if none, then use the DLL config settings?
So where will it look for app.config if I have a .Net DLL in the GAC that is begin called from a VB6 exe via COM interop? Probably nowhere I guess.
The solution seems to be to use a custom config file for your DLL app settings. However my DLL is using a web-service and the .Net web service tool puts the web service URI into, you guessed it, the app.settings file for the DLL. I want access to the app.config so I can change the web service URI to point to a different web service. Again, I can get around it by setting the web service URI manually in the code, but I'm starting to fight the framework rather than use it!
So, create a DLL project (mine is called "TestAppConfigDll") and add it to your EXE project. Use the Settings designer again to add your app.config file to your DLL (right-clicking on the project, selecting "properties" and then choosing the "settings" tab). I'm going to add an "Application" setting called "MyDllVal". Again we get a pretty similar looking app.config file in our project:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section
name="TestAppConfigDll.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<TestAppConfigDll.Properties.Settings>
<setting name="MyDllVal" serializeAs="String">
<value>18.2</value>
</setting>
</TestAppConfigDll.Properties.Settings>
</applicationSettings>
</configuration>
And again, we can access the value in code using:
string myDllVal =
TestAppConfigDll.Properties.Settings.Default.MyDllVal;
No surprise to find that the config file in our bin folder (..\TestAppConfigDll\bin\Debug) is prefixed by the dll name, "TestAppConfigDll.dll.config" in my case. BUT looking in the bin for the EXE project (which references the dll and contains a copy of my dll file), there is no dll.config file, just the original exe.config. And the exe.config has no "MyDllVal" property. If I run the EXE it picks up the original value for "MyDllVal" but I have no way to modify it! It knows the original compile-time value because it has been hard-coded into the "Settings.Designer.cs" file that was generated when you entered your value via the Settings designer. Here is the code if you are interested (my original value was "18.2"):
[global::System.Configuration.
ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.
DebuggerNonUserCodeAttribute()]
[global::System.Configuration.
DefaultSettingValueAttribute("18.2")]
public string MyDllVal {
get {
return ((string)(this["MyDllVal"]));
}
}
So, what if I add a dll.config ("TestAppConfigDll.dll.config") under the EXE bin folder - will it read it on start-up? Nope - it doesn't read it.
So, maybe it is looking in the exe.config for my setting. What if I merge my "MyDllVal" setting into the exe.config file - will it read it on start-up? Wooeee! That works! So I had to take two chunks of xml from the dll.config to the exe.config; (i) the "section", and (ii) the "{dllname}.Properties.Settings". The resulting exe.config looks like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="applicationSettings"
type="System.Configuration.ApplicationSettingsGroup,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" >
<section
name="TestAppConfig.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
<section
name="TestAppConfigDll.Properties.Settings"
type="System.Configuration.ClientSettingsSection,
System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089"
requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<TestAppConfig.Properties.Settings>
<setting name="MyVal" serializeAs="String">
<value>17</value>
</setting>
</TestAppConfig.Properties.Settings>
<TestAppConfigDll.Properties.Settings>
<setting name="MyDllVal" serializeAs="String">
<value>18.00 combo</value>
</setting>
</TestAppConfigDll.Properties.Settings>
</applicationSettings>
</configuration>
So the upshot is, if the DLL is called from an EXE, then the DLL will try to get its app.config settings from the EXE's app.config file. Even if I remove the EXE's app.config, the DLL does not use the DLL's app.config file.
Man, this is annoying! Why have they done it this way? Maybe it is so that shared DLLs in the GAC can have different config settings for different EXEs. But even then, couldn't they have used the EXE config settings first, and if none, then use the DLL config settings?
So where will it look for app.config if I have a .Net DLL in the GAC that is begin called from a VB6 exe via COM interop? Probably nowhere I guess.
The solution seems to be to use a custom config file for your DLL app settings. However my DLL is using a web-service and the .Net web service tool puts the web service URI into, you guessed it, the app.settings file for the DLL. I want access to the app.config so I can change the web service URI to point to a different web service. Again, I can get around it by setting the web service URI manually in the code, but I'm starting to fight the framework rather than use it!
Subscribe to:
Posts (Atom)