This tutorial shows how to create a Web page and how to make this interact with an existing COBOL program. The page is generated in managed COBOL. The page calls an intermediary program to map .NET data types onto COBOL data types. The intermediary program then calls the existing COBOL program to perform the business logic.
The Web Site has three programs:
The first task is to create a Web Site, which you do as follows:
This creates the WebBook Web Site, which is then displayed in the Solution Explorer. The Web Site contains:
A Web Site appears in the solution explorer in a similar way to a project, but a Web Site is not a project. It is a directory, which enables you to publish the Web Site simply. For full details see the Visual Studio Help, such as the topic .NET Development\Web Applications. This tutorial shows some of the other differences, which include:
In this section, you paint the form. You can also examine the code generated. For basic help on painting a form, see the tutorial Tutorial: Developing .NET Managed COBOL.
To lay out the Web form, use spaces and new lines, in the same way as you do in a text editor or in HTML.
Control | ID Property | Text Property |
---|---|---|
Label | label1 | Stock Number |
TextBox | textBoxStockNo (the case is significant) | (blank) |
Label | label2 | Title |
TextBox | textBoxTitle (the case is significant) | (blank) |
Label | label3 | Price |
Label | label4 (the case is significant) | (blank) |
TextBox | textBoxPrice (the case is significant) | (blank) |
Button | button1 (the case is significant) | Search |
To display the properties right-click the label and then click Properties. You can then scroll to the relevant property and edit it.
Now you need to add the code for the button click, which needs to call the legacy COBOL program and to populate the form with the information returned.
method-id. "button1_Click" protected. local-storage section. 01 input-string string. 01 my-exception type "System.Exception". procedure division using by value lnkSender as object lnkEvent as type "System.EventArgs". set input-string to textBoxStockNo::"Text" try set my-book to type "BookWrapper.Book"::"Read"(input-string) invoke self::"PopulateForm"(my-book) catch my-exception invoke self::"DisplayException"(my-exception) end-try end method "button1_Click".
method-id. "PopulateForm" final private. procedure division using my-book as type "BookWrapper.Book". if my-book<>null set textBoxStockNo::"Text" to my-book::"StockNumber" set textBoxTitle::"Text" to my-book::"Title" set textBoxPrice::"Text" to type "System.Convert"::"ToString"(my-book::"RetailPrice") else set textBoxStockNo::"Text" to "****" set textBoxTitle::"Text" to "*************************************" set textBoxPrice::"Text" to "****" end-if end method "PopulateForm".
method-id. "DisplayException" private. procedure division using by value lnkException as type "System.Exception". set label4::"Text" to lnkException::"Message" set my-book to null invoke self::"PopulateForm"(my-book) end method "DisplayException".
You now need to add the existing COBOL code that contains the business logic, so that the form can use it. This code is supplied in a LegacyBook project containing book.cbl.
In addition, you need some wrapper code to convert the data from .NET types to COBOL types. The Web page uses .NET data types; these are System.String objects in our case. The book program uses COBOL types such as PIC X and PIC 99V99. The supplied program BookWrapper.cbl does this conversion, and you need to add this to the solution.
You now need to add some code to the form to call the wrapper code and to clear the last of the red squigglies to do with my-book.
01 my-book type "BookWrapper.Book".
You should now have no parsing errors, now that BookWrapper is declared. If you do have errors, check the supplied demonstration in Forms\WebBook to see where yours differs.
<!--The following code declares a section group for application configuration --> <configSections> <sectionGroup name="MicroFocus.COBOL.Application"> <section name="Switches" type="System.Configuration.NameValueSectionHandler" /> <section name="Environment" type="System.Configuration.NameValueSectionHandler" /> </sectionGroup> <!--The following code declares a section group for run-time configuration --> <sectionGroup name="MicroFocus.COBOL.Runtime"> <section name="Tunables" type="System.Configuration.NameValueSectionHandler" /> <section name="Switches" type="System.Configuration.NameValueSectionHandler" /> </sectionGroup> </configSections>
In the Web.config file, add the following text immediately after the <App_settings/> line:
<MicroFocus.COBOL.Application> <Switches/> <Environment> <add key="dd_bookfile" value="MyPath\bookfile.dat"/> </Environment> </MicroFocus.COBOL.Application>
Where MyPath is the path to the data file bookfile.dat, which is in the bin subfolder of the WinBook sample. See the \Forms\WinBook\bin subfolder in the examples.
The sample code is available in the Examples\Visual Studio Integration folder, with all the Visual Studio and .NET examples, and in the Forms subfolder.
The book.cbl program is a long-standing demonstration program that has been shipped with Micro Focus products for several years. It is written in procedural COBOL. The program reads and writes to an indexed file containing book records.
In this solution, the Book program is recompiled to managed code without any changes. Recompiling the program exposes it as a class and exposes its main entry point as a static method.
The program's Linkage section defines data as standard COBOL types, such as PIC X, which non-COBOL client programs will not understand. These types need to be mapped to .NET compatible types before communication with the client program. This mapping is done by the intermediary program BookWrapper.cbl.
The client Web form Default.aspx.cbl is generated as COBOL. The user enters data into the form and receives the return data there. The client form does the following:
The BookWrapper.cbl program acts as an intermediary between the pre-existing COBOL program book.cbl and the Web form. This enables you to leave the pre-existing COBOL unchanged.
The important point here is that you need to use compatible types when mixing languages. The Web form stores the data as .NET types and yet the Book program expects data as COBOL types.
The purpose of the BookWrapper program is to map your COBOL PICTUREs to .NET System.Strings. The program receives data from the Web form as System.Strings, and maps them onto standard COBOL data types before passing them to the pre-existing book program.
The object working storage declares the data items in a book record by using a copybook, as follows:
object. data division. working-storage section. copy "book-rec-dotnet.cpy" replacing == (prefix) == by == book ==. ...
The copybook book-rec-dotnet.cpy declares the book-details record. It declares book-title and book-stockno as COBOL pictures and also as properties so that Getter/Setter methods can be used to access them. The copybook contains:
01 (prefix)-details. 03 (prefix)-text-details. 05 (prefix)-title pic x(50) property as "Title". ... 03 (prefix)-stockno pic x(4) property as "StockNumber".
The following get property method gets a pointer to the book-details record:
method-id. get property "BookDetails". procedure division returning bookDetailsAddress as pointer. set bookDetailsAddress to address of book-details goback. end method.
The Read method is implemented in the static section as follows:
method-id. "Read". local-storage section. 01 file-status pic xx. procedure division using by value stockno-in as string returning myBook as Book. set myBook to new Book() set myBook::"StockNumber" to stockno-in call "BookLegacy" using by value readRecord by value myBook::"BookDetails" by reference file-status invoke "RaiseExceptionIfError" using file-status goback. end method "Read".
shows a .NET System.String, stockno-in, being passed in from client form. It also shows an instance of the Book class being returned. BookWrapper.cbl defines a new .NET type, Book, which can be used by programs written in any .NET language.
set myBook to new Book()
set mybook::"StockNumber"
takes the data from the .NET System.String (stockno-in) and stores it as the StockNumber property of myBook. This property is declared in the copybook as a picture string, and so the data is stored as a standard COBOL data type in book-stockno. The COBOL Compiler implicitly converts the data from the .NET string into a COBOL usage display item (pic x).
call "BookLegacy" using ...
calls the legacy program, book.cbl. It passes it the “BookDetails” property of myBook. If you look at the code in BookWrapper.cbl, you can see that what BookDetails does is pass a pointer to the BookRecord structure defined in book-rec-net.cpy. This structure matches the structure in the old book-rec.cpy, so what the legacy Book program sees is a book record being passed in by reference – which is what it expects. Book reads the stock number from this record, reads a record from the indexed file, and then puts the data in the other fields of the record.
invoke "RaiseExceptionIfError" using file-status
checks the file status returned from reading the file, and raises a .NET exception if there was an error. Exceptions are the standard .NET mechanism for signaling error conditions.