locked
Modifying output path for robotics applications RRS feed

  • Question

  • Hi,

    a very simple question before starting to develop a bit more "seriously". I've noticed all sample projects of MSRS have Visual Studio project properties page configured to start dsshost, "C:\Microsoft Robotics Studio (1.5)\" established as the working directoy of the service and output pointing to "C:\Microsoft Robotics Studio (1.5)\bin".

    I understand I can point project output to other folder without problems...in fact, I would like to have all assemblies and files related to my application a little bit more tidy, for example, under a particular folder, but not mixed among the hell of DLLs of Robotics runtime ("C:\Microsoft Robotics Studio (1.5)\bin"). Thus, I've changed the output of the project to "C:\Microsoft Robotics Studio (1.5)\bin\MyService".

    Deleted all old assemblies from "C:\Microsoft Robotics Studio (1.5)\bin" and rebuilt the project. I can see "MyService" folder has been created and almost all files and assemblies depending on the main application are copied there. However, MyService.Y2008.M02.proxy.dll and related assemblies (3 assemblies) are still copied to bin instead of "bin\MySerivice". And if I delete proxy related ones form that location, my application does not start neither from command-line nor compiles from Visual Studio.

    Reflection: Are robotics services and applications built with MSRS tied definitively to "C:\Microsoft Robotics Studio (1.5)\bin" folder? I'm thinking about future deployments of the application outside that particular directory and the problems I could run into, that's why I would like to get some feedback from experienced developers.

    Thanks very much in advance.
    Wednesday, March 12, 2008 3:36 PM

Answers

  • Hi Miguel and Rob,

     

    Sorry Miguel, I didn't know your name before, which I why I used the anonymous "original poster".

     

    This is starting to be a really interesting discussion.

     

    Rob --

    IMHO the /e qualifier on DssDeploy is either documented incorrectly or has a bug because I believe it works back to front. I've posted about this previously.

     

    As long as there is source code there, people who don't know any better will edit it. If the solution also recompiles other services, look out!

     

    Cloning is fairly messy. I have appended my notes to this message.

     

    Good on you for using an Apps folder! I'm glad to see I am not a voice crying in the wilderness.

     

    Miguel --

     

    For your config files, there are two approaches. Either put them in a "known" location, or put them with the manifest.

     

    For a fixed location, do this:

     

    Code Snippet

    private const string InitialStateUri = ServicePaths.MountPoint + @"/Apps/Organization/Config/ServiceName.Config.xml";

    ///

    /// ServiceName State

    ///

    [InitialStatePartner(Optional = true, ServiceUri = InitialStateUri)]

    private ServiceNameState _state = new ServiceNameState();

     

     

    Your config file will be located under MSRS in Apps/Organization/Config. Notice that the config file is optional so you have to check _state in your Start method to see if it is null, and if so then you should populate it with some default values. In this case, I suggest that you write out the new state using SaveState(_state).

     

    If you want to keep your manifests and config files portable, or have different ones for different people, then let each person create their own folder under MSRS somewhere, e.g. /Apps/Org/Users/JohnSmith.

    When they want to run a service, the would specify a manifest that resides in their personal folder:

     

    Code Snippet

    dsshost /p:50000 /t:50001 /m:"Apps/Org/Users/JohnSmith/myservice.manifest.xml"

     

     

    In the manifest, you specify the config file using an initial state partner:

     

    Code Snippet

     

        <ServiceRecordType>
            <dssp:Contract>http://some.uri/contracts/2008/01/mazesimulator.html</dssp:Contract>
            <dssp:PartnerList>
              <!--Initial config file -->
              <dssp:Partner>
                <dssp:Service>MazeSimulator.Config.xml</dssp:Service>
                <dssp:Name>dssp:StateService</dssp:Name>
              </dssp:Partner>
            </dssp:PartnerList>
        </ServiceRecordType>

     

     

    So now, when the service runs, in this case my Maze Simulator, it picks up the config file that is sitting right beside it in the same directory. Notice that there is no path specified in the filename.

    If you have a user interface that can modify the configuration (app settings) like I do for my modified Dashboard, then you can call SaveState() at any time to update the stored config file. You can even put it into your Drop handler. However, be careful because SaveState() posts a message and does not immediately write out the file, so you have to wait before finally exiting from your program or the state might not get saved. There was a thread about this a while ago.

     

    You can put anything you like into the state of a service, even if you never intend to modify it after the service starts up.

     

    Well, A$0.02 is currently worth about US$0.0186194 according to OANDA

     

    Trevor

     

    Cloning a Service

     

    1. Copy all files to a new folder. Note carefully that the folder must be at the same relative depth in the hierarchy. Otherwise try running DssProjectMigration to fix up the relative paths in the .csproj file.

     

    2. Rename all of the files that begin with the service name:
    xxx.cs
    xxx.csproj
    xxx.csproj.user
    xxx.manifest.xml
    xxx.sln
    xxxTypes.cs
    xxxState.cs (if it exists)

     

    3. Delete the .suo?

     

    4. Edit all these files and do a global search and replace of the old service name with the new name.

    DO NOT CHANGE THE CONTRACT IDENTIFIER LITERALLY!
    It is case-sensitive. Need to change it to all lower case. Then make sure that the same applies inside the manifest and also any config files and xslt files where the contract id is referenced.

     

    5. Edit any remaining .cs files to do a global search/replace.
    Form designer .cs files too because of the namespace.
    .resx files do not seem to need it.

     

    6. Other files

    Properties folder ???
    Resources folder ???
    Embedded resources need to be renamed like:
    xxxService.Image.PNG
    xxxService.Thumbnail.PNG

    Might be other files named with the old service name, e.g. css and xslt files.

     

    7. XSLT files present a potential problem -- what about the case of the the service name? Convert everything to lowercase. The case of the service state class is also important in an XSLT file and often will be mixed.

     

    8. Images cannot be simply renamed. Same for icons and other bitmap images (in Resources?)

     

    9. Load in Visual Studio.

    Check that the Project Properties still make sense --
    Application tab - Assembly name and Namespace
    Debug tab, etc.

     

    10. Compile and see what happens.

     

    Thursday, March 13, 2008 12:58 PM

All replies

  • To answer part of your question, once your project is built you can use dssdeploy to make it portable.  You can unwrap a deployment anywhere and it should work.  If you want to do things by hand, there is this must-read thread on DIY hosting which deals with some of the unusual details:
    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2344094&SiteID=1

    These build folder issues have long been a thorn in my side and I hope the 2.0 release takes some steps to fix them.  The biggest problems are that Debug and Release builds go to the same place, and if you are doing parallel development on different boxes then they have to be identical- it's a royal pain when MSRS is on drive C: on one box and D: on another.  dssprojectmigration is really only a one-time fix and it does bad things like blowing away any custom assembly signing keys.

    One issue that I'll be tackling shortly is the problem of creating a deployment in a multi-user context- will I be able to coerce the DSS environment to save persistent state files (*.config.xml) to a user's Application Data folders rather than somewhere under Program Files?  The DSS sandbox is, in principle, a nice idea, but it runs against the conventional standards for windows applications.

    $0.02

    Wednesday, March 12, 2008 5:24 PM
  •  

    Hi Guys,

     

    I'm glad somebody started a thread like this. I have been concerned about the explosion of files in the bin folder for some time.

     

    I think that the bin folder is pretty integral to the operation of MSRS in the current version, so it is not really possible to re-target your services to a different folder.

     

    A related problem is that manifests must be specified relative to the current path on the Desktop version. (I posted a note about creating a location independent batch file recently so you could run services from anywhere.) The behavior of dsshost in the Desktop and CF versions is different regarding the path to your manifests. They should be brought into line, and I suggest following the CF approach where the manifest path is always relative to dsshost.

     

    The C: versus D: problem is a pain in the you-know-what, but I think it is partially the fault of Visual Studio. I've tried using relative paths (lots of ../../../) but it seems to resolve the path and store the full path in the solution. Maybe I am wrong on this one and it is just me ...

     

    The sandbox principle is fine if you expect DSS nodes to run as services, possibly under a service account. At this stage in the evolution of MSRS though, I suspect that 9 out of 10 people are running DSS under their own account. For new users, this results in an intermixing of the manifests and config files.

     

    On a shared computer, e.g. computer labs at a school or university, there needs to be some easy way for users to take all of their "settings" and config files with them. I use a Config folder under my own development directory. Then I always specify an Initial State partner in my manifests because the config file is then assumed to be in the same folder as the manifest and you can keep them together.

     

    Here are a few more issues I'd like to throw in as well.

     

    Name Space Pollution

     

    Everyone knows that there is a .com domain name for every word in the English language and many of them are "dead" domains. I am concerned that the same thing might happen to the bin folder and eventually there will be clashes. How many versions of an "Explorer" service or a "Wander" service do we need? (I am just as guilty as anyone of creating services with names like this.) And what about "Demo" or "Test"?

     

    Sure, you can use the Year and Month to try to make the names unique, but then its hard to identify all of the services from a particular organization. Therefore I suggest that the naming convention for services should be extended to:

    Organization.Service.Year.Month

     

    This would at least mean that all the services from a particular organization would be grouped together when you looked at the directory contents. KUKA did this will all of their services, but it should not be left up to the developers.

     

    An alternative is to use sub-directories as the original poster tried to do. In this case, the first sub-level should be the name of the organization, so you would end up with:

    bin\Organization\Service.Year.Month.

     

    Whether there are more sub-levels is a matter for debate. This means that when the service directory is rebuilt it will have to recurse through all sub-folders.

     

    Code Separation

     

    Some time ago I tried to encourage people to put their source code into a folder structure like Apps\Organization\Servicename rather than everyone putting their files into samples\Servicename. I think that the samples folder should NOT be used for anything other than the code that ships with MSRS. (Maybe the name samples should be changed to Microsoft).

     

    A related issue is that newcomers edit the code in samples to try to understand how MSRS works. After several hacks, they can render an example inoperative, and then they can't put it back the way they found it because, being novices, they did not mark the changes they made in the code.

     

    I posted a suggestion for a "clone" tool a little while ago. This would help to solve the problem where people edit the existing examples by allowing them to easily make a copy into a different folder. I realise that it is not a trivial task to clone a service - I have done it myself by hand many times. But MSRS has some pretty incredible code anyway, like running a debugger using a web browser for VPL. Surely the problems of cloning a service can be solved.

     

    Overwritting of DLLs

     

    It worries me that DssDeploy does an Xcopy deployment. That means that it is not intelligent when it comes to DLL versioning. DLL Hell has returned with MSRS because of the strong-name requirement. For instance, I recompiled the sample Explorer service the other day and it recomplied the SICK Laser because that was also included in the Solution. (Don't get me started on that topic - I don't like multiple projects in a solution.) Then the LRF in the Simulator no longer worked! Because there is no way to rebuild the Simulator, I had to restore the SICK DLLs from a backup.

     

    I've also found that some of the packages out there include the DSS runtime, which is unnecessary if you are deploying into an existing installation. This could revert your DLLs to an older version of MSRS and is quite dangerous. I hate it when DssDeploy says it is about to overwrite 167 files, is this OK? Now I look at the packages first using the tool that Paul Roberts wrote called ViewDssDeployContents. (It's on Channel 9). If I am really paranoid, I back up the bin folder first.

     

    That's enough for now. I'm starting to ramble.

     

    BTW Rob, with inflation your $0.02 is now worth $2.00 :-)

     

    Trevor

    Thursday, March 13, 2008 1:46 AM

  • Actually, Trevor, that's $0.02 Canadian, which is like a million dollars these days. ;-)

    It looks like we've opened the whole can of worms. It's an interesting point you make about the dss environment running as a system service. I'll have to think a bit about what that might imply for per-user settings and how they can be managed. Surely there are other windows services that have to deal with this issue.

    Some other random comments:
    imho, dssdeploy should not package any MSRS dlls by default. It's a lot easier to add a command-line argument enabling portability than it is to clean up a blitzed installation. [The MSRS download statistics are certainly inflated by the number of times I've re-downloaded for this kind of thing.]

    Sample code: I can't think of a nice way to resolve these issues. There ought to be a big pop-up dialog somewhere stressing that the assembly and contract should be renamed before recompiling a sample.

    Service cloning: I remember that it is difficult but I don't remember why- is it not enough to rename the assembly and contract?  There might be other minor things like updating manifests, but a simple tool that does the basics would help.

    Namespaces, assembly names: the java crowd dealt with this a long time ago. We prefix all our assemblies with Vi_. Kuka's approach is even better. I think most vendors will make an effort to make their contracts/assemblies distinctive.

    Code separation: we've adopted the Apps/[Vendor]/ pattern for our sample code and documentation. I think this is a good approach, and better than polluting the MSRS-specific directories.

    That makes $0.04

    Thursday, March 13, 2008 5:09 AM
  •  Trevor Taylor wrote:

     

    I'm glad somebody started a thread like this. I have been concerned about the explosion of files in the bin folder for some time.


    Also glad to hear your opinions and see that all this is not new....

     

     Trevor Taylor wrote:

    I think that the bin folder is pretty integral to the operation of MSRS in the current version, so it is not really possible to re-target your services to a different folder.


    I supposed that. A very big mistake from MS.


     Trevor Taylor wrote:

    The sandbox principle is fine if you expect DSS nodes to run as services, possibly under a service account. At this stage in the evolution of MSRS though, I suspect that 9 out of 10 people are running DSS under their own account. For new users, this results in an intermixing of the manifests and config files.


    I also think manifests and config files mixing is painful. There are so much files among so much DLLs. I just want things to be a little bit more tidy.

     

     Trevor Taylor wrote:

    On a shared computer, e.g. computer labs at a school or university, there needs to be some easy way for users to take all of their "settings" and config files with them. I use a Config folder under my own development directory. Then I always specify an Initial State partner in my manifests because the config file is then assumed to be in the same folder as the manifest and you can keep them together.


    I also pointed application more or lees the same configuration files problems in this post, after seeing you answer Trevor, sure you can help me a little bit. I just wanted a configuration file to go along with my application, just like in Winforms application. I need my application to be very configurable (the IP address of a PC hosting services can change), so I need to make changes to this configuration file without needing to recompile.


     Trevor Taylor wrote:

     Name Space Pollution, Code Separation, Overwritting of DLLs


    The reflection here is clear for me (glad to see not only for me): MS should think and worry about these problems for future releases. I think MSRS should carefully think about development and deployment issues (folders, DLL hell, "bin" directory dependencies). For namespaces and naming conventions for DLLs, I agreee that Java could be a good mirror.....

     

    0.02 € , nowadays better than $ ;-)


    ---------

    Miguel

    Blog: http://lonifasiko.blogspot.com


    Thursday, March 13, 2008 11:32 AM
  • Hi Miguel and Rob,

     

    Sorry Miguel, I didn't know your name before, which I why I used the anonymous "original poster".

     

    This is starting to be a really interesting discussion.

     

    Rob --

    IMHO the /e qualifier on DssDeploy is either documented incorrectly or has a bug because I believe it works back to front. I've posted about this previously.

     

    As long as there is source code there, people who don't know any better will edit it. If the solution also recompiles other services, look out!

     

    Cloning is fairly messy. I have appended my notes to this message.

     

    Good on you for using an Apps folder! I'm glad to see I am not a voice crying in the wilderness.

     

    Miguel --

     

    For your config files, there are two approaches. Either put them in a "known" location, or put them with the manifest.

     

    For a fixed location, do this:

     

    Code Snippet

    private const string InitialStateUri = ServicePaths.MountPoint + @"/Apps/Organization/Config/ServiceName.Config.xml";

    ///

    /// ServiceName State

    ///

    [InitialStatePartner(Optional = true, ServiceUri = InitialStateUri)]

    private ServiceNameState _state = new ServiceNameState();

     

     

    Your config file will be located under MSRS in Apps/Organization/Config. Notice that the config file is optional so you have to check _state in your Start method to see if it is null, and if so then you should populate it with some default values. In this case, I suggest that you write out the new state using SaveState(_state).

     

    If you want to keep your manifests and config files portable, or have different ones for different people, then let each person create their own folder under MSRS somewhere, e.g. /Apps/Org/Users/JohnSmith.

    When they want to run a service, the would specify a manifest that resides in their personal folder:

     

    Code Snippet

    dsshost /p:50000 /t:50001 /m:"Apps/Org/Users/JohnSmith/myservice.manifest.xml"

     

     

    In the manifest, you specify the config file using an initial state partner:

     

    Code Snippet

     

        <ServiceRecordType>
            <dssp:Contract>http://some.uri/contracts/2008/01/mazesimulator.html</dssp:Contract>
            <dssp:PartnerList>
              <!--Initial config file -->
              <dssp:Partner>
                <dssp:Service>MazeSimulator.Config.xml</dssp:Service>
                <dssp:Name>dssp:StateService</dssp:Name>
              </dssp:Partner>
            </dssp:PartnerList>
        </ServiceRecordType>

     

     

    So now, when the service runs, in this case my Maze Simulator, it picks up the config file that is sitting right beside it in the same directory. Notice that there is no path specified in the filename.

    If you have a user interface that can modify the configuration (app settings) like I do for my modified Dashboard, then you can call SaveState() at any time to update the stored config file. You can even put it into your Drop handler. However, be careful because SaveState() posts a message and does not immediately write out the file, so you have to wait before finally exiting from your program or the state might not get saved. There was a thread about this a while ago.

     

    You can put anything you like into the state of a service, even if you never intend to modify it after the service starts up.

     

    Well, A$0.02 is currently worth about US$0.0186194 according to OANDA

     

    Trevor

     

    Cloning a Service

     

    1. Copy all files to a new folder. Note carefully that the folder must be at the same relative depth in the hierarchy. Otherwise try running DssProjectMigration to fix up the relative paths in the .csproj file.

     

    2. Rename all of the files that begin with the service name:
    xxx.cs
    xxx.csproj
    xxx.csproj.user
    xxx.manifest.xml
    xxx.sln
    xxxTypes.cs
    xxxState.cs (if it exists)

     

    3. Delete the .suo?

     

    4. Edit all these files and do a global search and replace of the old service name with the new name.

    DO NOT CHANGE THE CONTRACT IDENTIFIER LITERALLY!
    It is case-sensitive. Need to change it to all lower case. Then make sure that the same applies inside the manifest and also any config files and xslt files where the contract id is referenced.

     

    5. Edit any remaining .cs files to do a global search/replace.
    Form designer .cs files too because of the namespace.
    .resx files do not seem to need it.

     

    6. Other files

    Properties folder ???
    Resources folder ???
    Embedded resources need to be renamed like:
    xxxService.Image.PNG
    xxxService.Thumbnail.PNG

    Might be other files named with the old service name, e.g. css and xslt files.

     

    7. XSLT files present a potential problem -- what about the case of the the service name? Convert everything to lowercase. The case of the service state class is also important in an XSLT file and often will be mixed.

     

    8. Images cannot be simply renamed. Same for icons and other bitmap images (in Resources?)

     

    9. Load in Visual Studio.

    Check that the Project Properties still make sense --
    Application tab - Assembly name and Namespace
    Debug tab, etc.

     

    10. Compile and see what happens.

     

    Thursday, March 13, 2008 12:58 PM