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.