Preparing Existing Code for Synergy .NET
In addition to using Synergy DBL to create entirely new applications for .NET Framework and .NET 6 and higher, you may also be able to use existing traditional Synergy code to create .NET applications.
Whether you are planning to migrate an entire application, port frequently used functionality, or simply make some Synergy routines available to other .NET programs, you can begin with an existing traditional Synergy solution.
- If you use xfServerPlus and xfNetLink .NET, you can rebuild your Synergy methods to run under Microsoft .NET Framework on Windows and then call them natively (without going through xfNetLink .NET and xfServerPlus). See Converting xfServerPlus routines for native .NET access.
- If you use the Synergy windowing API, you can use Synergy .NET’s support for this API as a starting point for your user interface. This results in “Unix-like” non-mouse-controlled “W_” windows in WinForms under the .NET Framework on Windows.
The following steps outline the basic procedure for a typical application. This is an iterative process; you start with global entities, move to common code, and then work up to code that’s specific to certain functionality. The goal is to organize code into useful projects and avoid circular dependencies and forward references, which are not allowed in DLLs (see step 7), while making code compatible with .NET.
Unlike traditional Synergy,
- all global symbols must be resolved at the time an assembly (class library or executable) is compiled, because all files in an application are compiled together. (With traditional Synergy, the same name can be used for different global entities in different .dbl files if the files are compiled separately.)
- it is not possible for a global record in an .exe file to be referenced by an external record in a class library.
To prepare existing traditional Synergy code for .NET in Visual Studio,
For more information on project templates, see Synergy/DE project templates.
2. | Once you’ve selected a template, specify a name, location, etc., for the project, and click OK to create it. |
3. | In the .dbl file for the project, create a subroutine and add all global entities for your application into the subroutine: |
- Add all global structures to the data division of the subroutine.
- Add global commons, global literals, global data sections, and INIT statements to the procedure division of the subroutine.
4. | Set project properties as necessary. See Synergy/DE project properties. |
- Is it necessary to the .NET solution, or can it be removed?
- Is it replaceable with code that functions in both Synergy .NET and traditional Synergy? If not, you can use the following compile-time defines to conditionally compile code of the program (see Compile-time defines).
Don’t be alarmed if your initial compilations result in a number of errors and warnings. Most of the errors and warnings will involve only minor fixes, and solving one will most likely also resolve several others. Also keep in mind that many of these issues would result in runtime failures—and they may already be causing runtime errors in your current application.
See Synergy DBL Support for .NET for information on Synergy features that are not supported in Synergy .NET.
6. | Repeat the process (step 1 through step 5) for your application’s core routines, and add a project reference to the project for global structures, commons, etc. |
With Synergy .NET, only forward references are supported (i.e., circular references are not allowed). For example, if you have core routines and order entry routines in separate projects and the order entry routines call the core routines, the core routines cannot reference anything in the order entry routines. There is an exception: you can use XSUBR for a “backward reference” if necessary, but this can adversely affect performance.
8. | Create projects for the routines that make up the programs that call the routine libraries and add project references to those libraries. These programs will be executable assemblies, so create application projects for these programs. Then repeat the process described in step 5 for these projects. |
9. | Once you can build (i.e., once compile errors have been corrected for the projects), you should be able to run and debug the application. |
Converting xfServerPlus routines for native .NET access
If you use xfNetLink .NET to access Synergy routines, you can access these routines natively in Microsoft .NET Framework on Windows by generating an assembly for the Synergy routines and then accessing that assembly (rather than the assembly generated by gencs). Once you make this change to your application, it will no longer be a distributed application that accesses Synergy routines remotely. Rather, those routines will be built into a DLL, which will be referenced locally by the .NET Framework application (the application that was the xfNetLink .NET client). Neither xfNetLink nor xfServerPlus will be involved.
This conversion can be of benefit if your xfNetLink client application is a Windows application (e.g., written in C# or VB). It should improve performance and enable you to use seamless in-process debugging from your client code through to the Synergy .NET code. It should also help you prepare for future .NET development. For a web application, you can either continue to access Synergy routines remotely from your .NET client, or if your web server is Windows based, you can convert to run natively without xfServerPlus / xfNetLink .NET.
For web services (IIS and WCF), globals, channels, and server connections must be isolated by AppDomain. For more information, see Using Synergy .NET in Multi-Threaded Applications, available on the Synergex blog, and see SynNetAspAppDomainOnlyInterop, available from Synergy CodeExchange in the Synergex Resource Center. |
To convert xfServerPlus routines for native .NET Framework access,
1. | Create a Synergy/DE interop project in Visual Studio. (In the New Project window for Visual Studio, select Synergy/DE > Interop.) You can add this project directly to the client solution, or you can create a separate solution (and later add a reference to it from the client). |
The project will include the file SynergyRoutines.dbl, which has stub routines for XFPL_LOG and SET_XFPL_TIMEOUT so that if your Synergy code calls these two xfServerPlus API routines, it won’t break. SynergyRoutines.dbl also includes some datetime conversion routines that are used by the generated classes. Do not alter these routines and do not remove this file from the project.
If your xfNetLink client program calls XFPL_REGCLEANUP directly, you will need to find some other way to incorporate that functionality. For example, you could change your code to directly call the cleanup routine that was called by XFPL_REGCLEANUP. |
2. | Add the source files that contain the Synergy routines currently accessed by your xfNetLink .NET application to the project. |
3. | If your Synergy routines have not yet been modified to use attributes, parameter modifiers, and (optionally) documentation comments, do so now. See Using attributes to define Synergy methods. |
- Add direction (IN, OUT, INOUT) and required/optional (REQ, OPT) modifiers to parameters. See Defining a parameter.
- Add xfMethod attributes. For details, see xfMethod attribute.
Only the interface property of the xfMethod attribute is required when attributing code in an interop project, but you may need other properties, such as method name, depending on your code. The elb, id, and encrypt properties are unnecessary. Pay special attention to how methods are named so that you do not break existing code. If you’ve already attributed your code, including properties such as elb and id, you can leave it as is; these are not necessary when using the interop project type, but they do no harm.
Pay special attention if you choose to rely on default sizes for return values when attributing code, as the data type conversion from Synergy to C# types sometimes depends on the defined size. See Appendix B: Data Type Mapping for xfNetLink Java for details on data type mapping.
If you used the alternate interface name feature, you will need to specify the alternate name for the interface property when you attribute your code. For example, if the interface for the log-in routine was Cust in the SMC and you always changed it to Customer when you generated classes, you would use Customer for the interface property in the xfMethod attribute. Or, if you generated classes once with Cust and a second time with Vendor, you’d create two xfMethod attributes for the log-in routine, one for each interface. See Attribute examples for an example. |
- Add xfParameter attributes as needed. For details, see xfParameter attribute.
If your Synergy routines pass structures as ordinary parameters or as arrays, redefine them as structfields.
As with return values, if you rely on default sizes for parameters when attributing code, you should pay special attention, as the data type conversion from Synergy to C# types sometimes depends on the defined size. See Appendix B: Data Type Mapping for xfNetLink Java for details on data type mapping.
- Add Select classes to access your remote (or even local) data instead of READ, READS, etc., and ensure xfSeries is enabled. Using Select causes the database (rather than the program) to filter the returned records. See System-Supplied Classes for more information about the Select classes. Note that the SparseRecord method and the Select.OrderBy class offer additional performance benefits to Select class implementations.
- Add documentation comments, if desired. See Documentation comments.
4. | Set project properties. |
- On the Interop tab, you’ll find some of the options that you used to set in the Component Information dialog in Workbench (or specify on the command line). You should set these options the same way you did previously so as not to break code. For help with the fields on this tab, press F1 while the tab is displayed. Note the following:
- Prior to version 9.5, output parameters were always generated as “out” in the C# classes. If you change to “ref”, you will need to update your client code.
- If you previously used pooling, you should select the pooling option. This will ensure that any pooling support methods your application relied on are still called.
- On the Application tab, verify that the value in the Default namespace field matches the namespace your application currently uses. It defaults to the project name; previously, it defaulted to the project (or assembly) name followed by “NS”.
- To generate an XML file for API documentation, select the option on the Build tab.
5. | Set environment variables used by the Synergy routines. See Environment variables and Visual Studio development. If your application passes structures as parameters, be sure to specify the location of the repository files. See Using Synergy/DE repositories in Visual Studio. |
6. | Build the interop project to generate the wrapper classes and the assembly. Fix any issues reported by the compiler (see step 4 for more information). The generated classes are added to the project. Note that the classes and assembly are generated in one step rather than two as they were in Workbench. |
If you previously edited the generated classes, you will need to find some other way to include the added (or altered) functionality into your application. Because classes are generated and the assembly is built all in one step, any changes you make to the classes will be overwritten when you rebuild. |
7. | Update your client application: |
- Open projects for assemblies that used xfServerPlus and remove the references to the previous assembly and to xfnlnet.dll.
- Add a reference to the new assembly.
- Rebuild the project and run the application. You may need to set environment variables needed at runtime that were previously set on the xfServerPlus machine.
Your files will include unnecessary code. For example, there may be calls to the connect() and disconnect() methods, which are no longer used. The DLL you built in the interop project has stub routines to handle these calls (by doing nothing), but you may want eventually to remove the unnecessary calls so that your code is easier to read.