0

I am a student worker currently close to the finish line of a project I have been working on. Right now I'm implementing the .net Auto generated Api help pages. The nuget package WebApiTestClient does most of this for me. In the test calls however my manager wants certain fields to have options to choose from. So I want a dropdown with populated values vs the default text input.

This package creates the test dialog using knockout, and I'm okay with creating some knockout templates to get the knockout to work, or completely writing my own java script to run the test dialog.

I have attempted several ways to solve the problem. One using attributes and codes to reach out to service and extend the Model used to generate the pages. This worked but had caching, and dependency issues, plus the added headache of mapping an enum to data-calls, which I don't like the idea of anyway.

The option I'm exploring is to modify the HelpPageSampleGenerator the nuget package gives you to handle this. There is a config that runs on start that adds things like custom samples for Type to the HelpPageSampleGenerator. Hopefully I could create the custom inputs here.

Another options I have thought of but haven't explored yet is using attributes to map to custom input templates and calling APIs to get the options from there and creating the input. I would have to do more code in a view than I would like to but if I call the API itself I won't have to worry about dependency issues, and this seems very flexible for the UI.

If anyone has done something similar or has any knowledge of the framework that would make this easier that would be very appreciated. I may be making this harder than it needs to be this is new territory for me. Thank you to anyone who took the time to read this.

EDIT: Purged and cleaned the question since it was too long and there were no responses to the old questions that could make ongoing conversation confusing to new viewers.

1 Answer 1

0

It seems that I was overthinking the problem. I was stuck on solving this with some attribute or an advanced way because it seemed on the surface like the best approach and the package is already doing some fancy reflection and documentation reading.

For anyone using this package WebApiTestClient and wanting to have more robust test input options in the test dialog here is the solution I went with.

Involved parts: There are several code pieces the package gives you that will need to be changed. These are all minor changes.

HelpPageApiModel: This model is used to generate all the pages this nuget package scaffolds you will need to extend this model to be able to change the pages. My change was the addition of a field ApiParameterOptions which held a Dictionary<string,CustomModel> string was nameof({specificUriParameter})

CustomModel: This model contains information relevant to the input type and their options. This part is up to you. Mine simply had two fields InputType an enum that had options for a MultiSelect, Text, or Dropdown inputs, and InputValueCollection which was a Dictionary<string,string> the InputValueCollection could be used to populate dropdown lists the Dictionary<string,string> was meant to be populated accordingly <value,displaytext>

HelpPageSampleGenerator: This is used to generate samples for specific types or specific APIs. This seemed like the most appropriate place to hold information for the input options because the package author had already handle problems of persistence and the data flow so when the model was being generated we could access this object to add the additional data to the model. The modification here was again a simple field addition Dictionary<HelpPageSampleKey,CustomModel>. The HelpPageSampleKey was something the package author was using to key Api information.

Generating the additional info: The data is going to be passed through several layers, as far as I know this is the best way of handling it, and the way the package author had handled similar problems. Again you will need to make several minor changes to the file provided in the package.

HelpPageConfigurationExtension: You will need to add a static function here, or in another file. I called mine GenerateApiParameterOptions the function should look similar to this

    private static void GenerateApiParameterOptions(string controllerName,string actionName,HelpPageApiModel apiModel,HelpPageSampleGenerator helpPageSampleGenerator)
    {

        var dictionary = apiModel.ApiParameterOptions;
        foreach (var apiParam in apiModel.ApiDescription.ParameterDescriptions)
        {
            if (apiParam.Source == ApiParameterSource.FromUri)
            {
                if (apiParam.ParameterDescriptor.ParameterType.IsValueType ||
                    apiParam.ParameterDescriptor.ParameterType == typeof(string))
                {
                    dictionary.Add(apiParam.Name, new HelpTestInputModel
                    {
                        InputType = HelpInputType.Text,
                        InputValueCollection = new Dictionary<string, string>()
                    });
                }
                else
                {
                    var properties = apiParam.ParameterDescriptor.ParameterType.GetProperties();
                    foreach (var property in properties)
                    {
                        var key = new HelpPageSampleKey(SampleDirection.Response, controllerName, actionName,
                            new List<string> { property.Name });
                        HelpTestInputModel model;
                        if (helpPageSampleGenerator.ActionParametersTestInput.TryGetValue(key, out model))
                        {
                            dictionary.Add(property.Name, model);
                        }
                        else
                        {
                            dictionary.Add(property.Name, new HelpTestInputModel
                            {
                                InputType = HelpInputType.Text,
                                InputValueCollection = new Dictionary<string, string>()
                            });
                        }
                    }
                }
            }
        }
    }

You will have to call this in the static GenerateApiModel function that is in the file. Call it after all the other Generate functions have been called. One thing that I did not do that here that I may add later is track whether the Parameter is required or not, but I would have to create a new composite model to do so. I will explain why later.

This is the most complicated piece of code that needs to be added I'm sure others smarter than me could pretty this up as well.

The next function that needs to be added is and extension method. It should look similar to this

    public static void SetApiHelpParameterOptions(this HttpConfiguration   config, HelpTestInputModel helpTestInputModel, string controllerName, string actionName, string paramterName)
    {
             //HelpPageSampleGenerator().WhateverDictionaryAutoProp you made that holds the values for the HelpApiParameterOptions.
             config.GetHelpPageSampleGenerator().HelpApiParameterOptions.Add(new HelpPageSampleKey(SampleDirection.Response,controllerName,actionName,new List<string>{paramterName});
    }

This creates a an in the HelpPageSampleGenerator used to generate the HelpPageApiModel. I may be misusing the HelpPageSampleKey and might look for other ways to key this data but it is working for now.

Adding the special option: Now in your HelpPAgeConfig file in the HelpPage Area's App_Start folder you can add these special options to your by calling generating the models and passing them to the new extension method.

ex: config.SetApiHelpParameterOptions(model,"cName","aName","pName");

The worst part is over now all that is left to do is generate the view.

Generating the View with the new Model: If you want to change as little as possible with the views then read the rest. You may want to completely change the way the dialog is generated and create all your own javascript that is up to you. You now have a model that has all the information you need to do this.

Unless you went way crazier than I did with your additions there should be only two files that need to be changed. The View used to generate the Test dialog is in a folder called DisplayTemplates the View is TestClientDialogs.cshtml

There will be two major changes that need to be made to this file. First the approach in this view is somewhat strange. The package author generates a json object in a script tag dynamically from the model. We will change the way on property is generated. UriParameters[]

    UriParameters: [ 
        @foreach(var input in Model.ApiParamterOptions){
        var template = input.Value.InputType == HelpInputType.Dropdown ? "dropdown-input-template" : "text-input-template";
        @:{ name:"@input.Key", value:"",required:@input.Value.Required.ToString().ToLower(), inputOptions:@Html.Raw(input.Value.InputValueCollection.ToJsonString()), inputTemplate: "@template"
        }],

I somewhat simplified this and use the made up method ToJsonString(). Since this page uses knockout.js you will have to create knockout templates of the same names you gave there, and change from using a simple knockout foreach to a knockout dynamic template with a foreach. This is relatively simple but requires a working knowledge of the framework.

Next you will have to change there knockout code. Which is a simple as creating and binding the new values you are using to their model, and accounting for the possibility of collections. The two parts I needed to change in the provided WebApiTestClient.js file were the line self.UriParamters.push(....), to add and bind the new parameters, and the function BuildUriPath it may be different for you.

After all that is done you now have a test dialog with the ability to add populated dropdowns. I am marking this as the answer but if anyone else has any suggestions or other solutions please let me know. I hope this help anyone having a similar problem. If I made any glaringly bad decisions please let me know.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.