Resolved Web API Question

robertb_NZ

Well-known member
Joined
May 11, 2010
Messages
146
Location
Auckland, New Zealand
Programming Experience
10+
I have spent some time working with the tutorial Create web APIs with ASP.NET Core as recommended in my previous query. I'm now trying to generate a client to invoke CICS web service JSPG2 but I'm having trouble with getting my API test to generate.

Program JSPG2 is an operation within service MyJSv, so I generated an API project called MyJSv and I'm trying to create a controller for JSPG2 within this. Program JSPG2 is invoked by posting input message IJSPG2, and responds with an output message OJSPG2. From my SoapUI tests I had example JSON for the input and output messages, and I've created classes IJSPG2.cs and OJSPG2.cs in the Models folder. I added and registered a database context. So far so good.

Now I reach the tutorial stage Scaffold a Controller. I select API Controller with actions, using Entity Framework and, in the dialog, selected
Model Class IJSPG2 (MyJSv.Models)
Data Context Class: JSPG2Context (MyJSv.Models)

Visual Studio reacted with an error: -
There was an error running the selected code generator:
The entity type 'IJSPG2' requires a primary key to be defined.
If you intended to use a keyless enitity type call 'HasNoKey0'

This error persisted even after I added [Key] to the definition. IJSPG2.cs is defined
C#:
using System.ComponentModel.DataAnnotations;
namespace MyJSv.Models
{
    public class IJSPG2
    {
        public string JZ_Function { get; set; }
        public int JZ_Employee_Skip { get; set; }
        public class JZEmployee
        {
            [Key] public string EMPNO { get; set; }
            public string FIRSTNME { get; set; }
...
            public string JZ_CURRENCY { get; set; }
        }
        public class ViewState
        {
            public string CheckSum_Employee { get; set; }
        }
    }
}

Where do I go from here? I'm wondering if I should have used "API Controller, Empty" or perhaps "API Controller with actions" instead of "API Controller with actions, using Entity Framework". Also, do I need to have all the database context of the tutorial for the situation where all I want to do is to send IJSPG2 as a json request message, and handle a json response which can be formatted to OJSPG2. Using database code, even in memory, seems to me to be unnecessary overhead even if I can get it to work.

Thank you for helping, Robert.
 
Why is JZEmployee nested inside IJSPG2? I see a Key attribute in the inner class but not in the outer class, which is the one the error message is complaining about.
 
I'm wondering if I should have used "API Controller, Empty" or perhaps "API Controller with actions" instead of "API Controller with actions, using Entity Framework".
I've never actually created a Web API project but I would assume that, if you want to use EF and don't have or want to create an EF model elsewhere in your program, the latter would be the option to use.
Also, do I need to have all the database context of the tutorial for the situation where all I want to do is to send IJSPG2 as a json request message, and handle a json response which can be formatted to OJSPG2.
You need to have everything that you want to use. You don't need entity classes that you will never use.
 
Thanks for responding. The reason that JZEmployee is nested inside IJSPG2 is that this reflects the structure of the web service message. I hadn't realized that [key] had to be applied to an outer class. EMPNO is the only class to which a key attribute could have been relevant - it is the primary key of the Employee record in the DB2 database.

However I think that all of this must be irrelevant as there is no database on the client side. I think I was confused by the tutorial, which does create a database of TodoItem. I'd assumed that one needed the database context to manage the Web API interface, but now I think that this was just a particular feature of the tutorial's example, and not fundamental to a web API. Here I have just request and response messages, and without a database I shouldn't need a key. I'll try again using API Controller with Actions. I'll post again when I've worked this through to either report that this is the answer, or to report that it's not.
 
It would be fairly rare that a web service was not backed by a database so you'll find that almost all examples will do so. The service itself doesn't care though. The data comes in and goes out the same way. What happens to that data inside the service is like what happens in any application, i.e. it could be anything but is very likely to involve a database.
 
Thanks John, that's worth noting.

My current task is to generate client-side interfaces for CICS Web Services like JSPG2, so I need to understand the minimal Web API code to make this happen. Obviously any database used by a CICS Web Service will exist on a "mainframe", and won't be accessible to client-side code. This diagram shows what I'm trying to do
WebAPI.jpg


My documentation that goes with this feature will have to make it clear what you MUST do, which are the tasks that you have to do to generate the interface, and differentiate this from what you MAY do, which is the logic that you write into the Client Program on the left. That means that first I have to thoroughly understand it myself. A database context as in the tutorials is an optional Client Program feature I think, and I didn't properly understand this when I went through the tutorial. Learning C#, .NET CORE, and Web Api all at once is making my brain hurt :)

BTW, when I used "API Controller with Actions" instead of "API Controller with Actions using Entity Framework" I made progress, getting past the error "The entity type 'IJSPG2' requires a primary key to be defined" above. Next challenge is to work out what I write into the POST method, to get it to work, so right now I'm going through pages about Web API. There'll probably be more questions before I'm through. Thank you for helping.
 
The tutorial's POST code within TodoItemsController (derived from ControllerBase), which was generated using API Controller with Actions Using Entity Framework, and then slightly modified, was
C#:
        // POST: api/TodoItems
        [HttpPost]
        public async Task<ActionResult<TodoItem>> PostTodoItem(TodoItem todoItem)
        {
            _context.TodoItems.Add(todoItem);
            await _context.SaveChangesAsync();

            //return CreatedAtAction("GetTodoItem", new { id = todoItem.Id }, todoItem);
            return CreatedAtAction(nameof(GetTodoItem), new { id = todoItem.Id }, todoItem);
        }
The equivalent code within MyJSvController, also derived from ControllerBase but generated using API Controller with actions, is
C#:
        // POST api/<JSPG2Controller>
        [HttpPost]
        public void Post([FromBody] string value)
        {
        }
I have a class IJSPG2.cs that describes the input that I want to send, as JSON, to http://localhost:9003/cics/services/JSPG2, and a class OJSPG2.cs that describes the JSON that is returned. So what do I write in this POST method? What would the code look like that converts JZSPG2.cs to JSON and posts it to the URL, then receives the response and converts it from JSON to OJSPG2.cs?
 
Back
Top