A means of defining and executing sets of data
C# JavaScript HTML PowerShell
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src updating assemblyinfos Mar 4, 2016
.gitignore
LICENSE.md
readme.md

readme.md

Test Data

Install Core

Install-Package TestData.Interface

Web Api Support

Install-Package TestData.Interface.Web

MediatR Support

Install-Package TestData.Interface.MediatR

Csv (FileSets) Support

Install-Package TestData.Interface.Files

Angular front end

This is designed to work with the webapi TestDataController which uses the attribute route prefix /api/testdata. However you could use any backend provided it accepts and returns data in the expected format. The test data UI is served on the client route: /testdata.

bower install ng-test-data --save

TestDataController returns a list of datasets in this format. It accepts a get request with no parameters.

descriptors.Select(d => new
  {
      Dependencies = d.Dependencies.Select(t => t.FullName),
      d.Name,
      d.Description,
      d.Type.FullName,
      TypeName = d.Type.Name,
      Properties = d.Properties.Select(p => new
      {
          FieldName = p.MemberInfo.Name,
          p.Property.Name,
          p.Property.Description,
          p.Property.DataType,
          p.Property.Required
      })
  }

DataSet request payloads should match below. It makes a post request.

public interface IDataSetRequest
{
    string DataSet { get; }
    IDictionary<string, IDictionary<string, string>> Properties { get; }
}

Configuring your angular application

You will need to require the module test-data and register a constant called apiBase. Do not include a trailing forward slash. This is the base path used to make the request e.g. /api becomes /api/testdata.

angular.module('app', ['ngTestData'])
  .constant('apiBase', '/api');

Configuring for AutoFac and MediatR

//Assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name.StartsWith("demo") || a.GetName().Name.StartsWith("TestData")).ToArray();

void RegisterTestData(ContainerBuilder builder)
{
    builder.RegisterApiControllers(typeof(TestDataController).Assembly);
    builder.RegisterTypes(Assemblies.SelectMany(a => a.GetTypes()).Where(x => !x.IsAbstract && typeof(IDataSet).IsAssignableFrom(x)).ToArray());

    builder
        .Register<Func<Type, IDataSet>>(x =>
        {
            var scope = x.Resolve<ILifetimeScope>();
            return (t) => scope.Resolve(t) as IDataSet;
        })
        .InstancePerRequest();

    builder
        .Register(x =>
        {
            var mediator = x.Resolve<IMediator>();
            var dispatcher = new MediatRDispatcher(mediator);
            return dispatcher;
        })
        .As<IDispatcher>()
        .InstancePerRequest();
}

DataSets

The string returned from a dataset is returned to the client (to be used as feedback).

Sample DataSet

This example is a bit contrived but demonstrates specifying a property and making use of it.

[DataSet("Cities", "A list of cities")]
public class CityDataSet : IDataSet
{
    private readonly IDbContext _dbContext;

    public  CityDataSet(IDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [DataSetProperty("Prefix", DataType.String, "Prefix the city name")]
    public string Prefix { get; set; }

    public async Task<string> Execute()
    {
        var city = new City
        {
            Name = Prefix + " Melbourne"
        };

        var cities = _dbContext.Set<City>();
        cities.Add(city);

        await _dbContext.SaveChangesAsync();

        return "Inserted 1 City";
    }
}

This example shows reading data from a CSV. The csv path is relative to the assembly containing the DataSet.

[DataSet("States", "A list of states")]
[DataSetDependency(typeof(CityDataSet))]
public class StateDataSet : IDataSet
{
    private readonly IDbSet<State> _states;

    public StateDataSet(IDbSet<State> states)
    {
        _states = states;
    }

    [DataSetProperty("Starts With", DataType.String, "Filter the states inserted", Required = true)]
    public string StartsWith { get; set; }

    [DataSetProperty("Created On", DataType.Date, "Date the states were created on")]
    public DateTime CreatedOn { get; set; }

    public async Task<string> Execute()
    {
        int count = 0;
        States.ForEach(stateRecord =>
        {
            if (StartsWith != null && !stateRecord.Name.StartsWith(StartsWith))
            {
                return;
            }

            var state = new State
            {
                Name = stateRecord.Name,
                CreatedOn = CreatedOn
            };
            count ++;

            states.Add(state);
        }, this);

        return String.Format("Inserted {0} States", count);
    }

    [FileDataSet("./data/states.csv")]
    public FileDataSetInstance<State> States { get; set; }
}