Closed nikmd23 closed 9 years ago
Glimpse serves resources to its various clients through the resource module. Examples of resources include the client JavaScript files, JSON data and other web assets.
From a high level, resources in Glimpse 2.0 will be pieces of middleware running on a branch of the middleware chain. That branch will be split off based on a configurable baseUri
, which will probably default to /glimpse
.
There are two API's available:
Both API's rely on Uri Template's (RFC6570) for specifying URL path & query string parameters.
To use the high level API, users must implement IResource
public interface IResource
{
Task Invoke(HttpContext context, IDictionary<string, string> parameters);
string Name { get; }
Parameters Parameters { get; }
}
An example implementation:
public class HelloWorldResource : IResource
{
public async Task Invoke(HttpContext context, IDictionary<string, string> parameters)
{
await context.Response.WriteAsync("Hello " + parameters["name"]);
}
public string Name => "Hello";
public Parameters Parameters => new Parameters(Parameter.Hash, +Parameter.Custom("name"));
}
The parameters collection, which is stubbed out below, is used for a resource to signal which parameters it would like passed in. The parameters
argument contains the result of parsing the URL for easy consumption.
The low level API tracks much more closely with standard middleware, and in fact, standard middleware can be used as a resource.
The interface to be implemented is IResourceStartup
:
public interface IResourceStartup
{
void Configure(IResourceBuilder resource);
}
A sample implementation:
public class HelloWorldResource : IResourceStartup
{
public void Configure(IResourceBuilder resource)
{
resource.Run("Hello", "?name={name}{&hash}", async (context, parameters) =>
{
await context.Response.WriteAsync("Hello " + parameters["name"]);
});
}
}
The low level API allows implementors to register multiple resources at once via IResourceBuilder.Run()
. Implementors can also access the IApplicationBuilder
via IResourceBuilder.Application
.
The full IResourceBuilder
is defined as follows:
public interface IResourceBuilder
{
IApplicationBuilder AppBuilder { get; }
//TODO: Add all Run overloads
IResourceBuilder Run(string name, string uriTemplate, Func<HttpContext, IDictionary<string, string>, Task> resource);
}
Both implementation of HelloWorldResource
would be available at /glimpse/hello/?name={name}{&hash}
. (Required name, optional hash.)
The low level API allows the implementer to construct the URI template exactly how they'd like.
Extension methods hanging off of context
will be provided to perform common tasks such as .ConfigureCors()
, .ConfigureCaching()
or .AddETag()
. These extension methods may be made available to IInspector
's as well
context
/// usage:
var x = new Parameters(+Parameter.Hash, -Parameter.Version, Parameter.Url, Parameter.Custom("foo", true), Parameter.Custom("bar", false));
Console.WriteLine(x.GenerateUriTemplate());
// output:
// ?hash={hash}&foo={foo}{&version,url,bar}
// implementation:
public class Parameter
{
// Example parameters, not the final list
public static Parameter Hash = new Parameter("hash");
public static Parameter Url = new Parameter("url");
public static Parameter Version = new Parameter("version");
public static Parameter RequestId = new Parameter("requestid");
public static Parameter Timestamp = new Parameter("stamp");
public static Parameter Callback = new Parameter("callback");
public Parameter(string name) : this(name, false)
{
}
public Parameter(string name, bool isRequired)
{
Name = name;
IsRequired = isRequired;
}
public static Parameter Custom(string name)
{
return new Parameter(name);
}
public static Parameter Custom(string name, bool isRequired)
{
return new Parameter(name, isRequired);
}
public string Name { get; private set; }
public bool IsRequired { get; private set; }
public static Parameter operator -(Parameter parameter)
{
return new Parameter(parameter.Name, false);
}
public static Parameter operator +(Parameter parameter)
{
return new Parameter(parameter.Name, true);
}
}
public class Parameters : List<Parameter>
{
public Parameters()
{
}
public Parameters(params Parameter[] parameters)
{
foreach (var parameter in parameters)
{
base.Add(parameter);
}
}
public new void Add(Parameter parameter)
{
base.Add(parameter);
}
public string GenerateUriTemplate()
{
var sb = new StringBuilder();
var requiredParams = this.Where(p => p.IsRequired).ToArray();
if (requiredParams.Length > 0)
{
sb.AppendFormat(@"?{0}={{{0}}}", requiredParams[0].Name);
for (int i = 1; i < requiredParams.Length; i++)
{
sb.AppendFormat(@"&{0}={{{0}}}", requiredParams[i].Name);
}
}
var optionalParams = this.Where(p => !p.IsRequired).Select(p => p.Name).ToArray();
if (optionalParams.Length > 0)
{
sb.Append(string.Format("{{{1}{0}}}", string.Join(",", optionalParams), requiredParams.Length > 0 ? "&" : "?"));
}
return sb.ToString();
}
}
Note, URI templates still need to be worked into the picture, but need to wait for further work to be done @darrelmiller. Will integrate as a separate PR when URI templates are ready.
I was able to run existing the PCL DLL under CoreCLR (profile 259 is compatible) and I am in the process of fixing the Nuget right now. Regarding parameter matching, I should have simple string parameters for path and query string working by Monday.
Sounds great mate! As you can see from the GenerateUriTemplate
method above, the default case we are providing for users is fairly simple. That said, it is only used by the higher level API and users can still define their own templates for the lower level one. So having support for the higher level one is enough for now and as you get more coverage for the other cases, we can allow the lower level one to work with more complex cases. Thanks again!
I just created a prerelease Nuget of UriTemplates that has a GetParameters(Uri) method that covers the basic scenarios that I believe you need. http://www.nuget.org/packages/Tavis.UriTemplates/0.6.5-beta
I'll look at brining these in tonight. Will update with how I get on.
We need to add back in the concept of resources that can serve assets and data.
In the past, Glimpse resources could:
Do we want to keep the same requirements for 2.0?