Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 31 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,70 +8,53 @@ Makes using ASP.NET Web API's self host with scriptcs easy as cake, much easier

## Highlights:

* Creates a pre-configured self host with the default route already added.
* Configures to allow resolving script controllers.
* Creates a pre-configured OWIN self host with the default routes already added.
* Supports configuring the OWIN pipeline
* Write your controllers as scripts
* Automatically imports common web api namespaces for you.
* Works as self hosted server or in OWIN

## Getting started with Web API using the pack

Disclaimer: Ultimately (soon) you will be able to install this via nuget and not have to clone / build / copy

* Create a new folder for your script i.e. c:\hellowebapi and change to it.
* Install the Web API script pack ```scriptcs -install -pre ScriptCs.WebApi```
* Install the Web API script pack ```scriptcs -install -pre ScriptCs.WebApi2```
* Create a start.csx and paste the code below

```csharp
public class TestController : ApiController {
public string Get() {
return "Hello world!";
}
using System.Dynamic;

public class TestController : ApiController
{
public dynamic Get() {
dynamic obj = new ExpandoObject();
obj.message = "Hello from Web Api";
return obj;
}
}

var webApi = Require<WebApi>();
var server = webApi.CreateServer("http://localhost:8080");
server.OpenAsync().Wait();

var webapi = Require<WebApi>();

var server = webapi.
Configure(typeof(TestController)).
UseJsonOnly().
Start("http://localhost:8080");

Console.WriteLine("Listening...");
Console.ReadLine();
server.CloseAsync().Wait();
server.Dispose();
```
* Running as admin type ```scriptcs start.csx``` to launch the app.
* Running as admin type ```scriptcs start.csx -modules mono``` on Windows or ```scriptcs start.csx``` on Mac/Linux to launch the app.
* Open a browser to "http://localhost:8080/api/test";
* That's it, your API is up!

Alternatively you can host the script pack in OWIN e.g.

```csharp
public class TestController : ApiController {
public string Get() {
return "Hello world!";
}
}

Require<OwinSelfHost>();

var webApi = Require<WebApi>();
var config = webApi.Create();

using ( OwinSelfHost.CreateServer("http://localhost:8080", app => app.UseWebApi(config)) ) {
Console.WriteLine("Listening...");
Console.ReadLine();
}
```


## Customizing
You can customize the host by modifying the configuration object.
Or if you would like to pass your own you can use the `CreateServer` overload.
Additional `CreateServer` overloads allow you to explicitly specify assemblies or `IHttpController` types you want to expose in your api:

You can configure the OWIN host by passing in an `Action<IBuilder>` to the `Configure` method
```csharp
// Use a custom configuration and specify controller types.
var config = new HttpSelfHostConfiguration("http://localhost:8080");
var controllers = new List<Type> { typeof(TestController) };
var server = webApi.CreateServer(config, controllers)
var server = webapi.
Configure(
typeof(TestController),
builder=> {
builder.Use<MyMiddleware>();
}
).
Start("http://localhost:8080");
```

## What's next
TBD
46 changes: 46 additions & 0 deletions samples/formatter.csx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Dynamic;
using System.Web.Http;
using System.Web.Http.Routing;

public class TestController : ApiController
{
public dynamic Get() {
dynamic obj = new ExpandoObject();
obj.message = "Hello from Web Api";
return obj;
}
}

var webapi = Require<WebApi>();

var formatter = webapi.NewFormatter().
SupportMediaType("application/vnd.foo+json").
MapUriExtension(".foo", "application/vnd.foo+json").
WriteToStream(async (args) => {
var writer = new StreamWriter(args.Stream);
await writer.WriteLineAsync("{\"foo\":\"foo\"}");
await writer.FlushAsync();
}).
Build();

var config = new HttpConfiguration();

webapi.
UseJsonOnly().
Configure(config, typeof(TestController));

config.Formatters.Insert(0, formatter);

config.Routes.Clear();
config.Routes.MapHttpRoute(name: "Extension",
routeTemplate: "api/{controller}.{extension}/{id}",
defaults: new {id = RouteParameter.Optional}
);

var server = webapi.Start("http://localhost:8080");

Console.WriteLine("Listening...");
Console.ReadLine();
server.Dispose();


17 changes: 17 additions & 0 deletions samples/packages.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Owin" version="5.2.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.OwinSelfHost" version="5.2.0" />
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net40" />
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" />
<package id="Microsoft.Owin" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Host.HttpListener" version="2.0.2" targetFramework="net45" />
<package id="Microsoft.Owin.Hosting" version="2.0.2" targetFramework="net45" />
<package id="Newtonsoft.Json" version="6.0.2" targetFramework="net45" />
<package id="Owin" version="1.0" targetFramework="net40" />
<package id="ScriptCs.Contracts" version="0.10.0" targetFramework="net45" />
<package id="ScriptCs.WebApi2" version="1.0.0" targetFramework="net45" />
</packages>
52 changes: 52 additions & 0 deletions src/ScriptCs.WebApi/Formatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Threading;
using System.Threading.Tasks;

namespace ScriptCs.WebApi
{
internal class Formatter : MediaTypeFormatter
{
private Func<Type, bool> _canReadType;
private Func<Type, bool> _canWriteType;
private Func<ReadFromStreamArgs, Task<object>> _readFromStream;
private Func<WriteToStreamArgs, Task> _writeToStream;

public Formatter(
Func<Type, bool> canReadType,
Func<Type, bool> canWriteType,
Func<ReadFromStreamArgs, Task<object>> readFromStream,
Func<WriteToStreamArgs, Task> writeToStream
)
{
_canReadType = canReadType;
_canWriteType = canWriteType;
_readFromStream = readFromStream;
_writeToStream = writeToStream;
}

public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger)
{
return _readFromStream(new ReadFromStreamArgs(type, readStream, content, formatterLogger));
}

public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
TransportContext transportContext, CancellationToken cancellationToken)
{
return _writeToStream(new WriteToStreamArgs(type, value, writeStream, content, transportContext, cancellationToken));
}

public override bool CanReadType(Type type)
{
return _canReadType(type);
}

public override bool CanWriteType(Type type)
{
return _canWriteType(type);
}
}
}
157 changes: 157 additions & 0 deletions src/ScriptCs.WebApi/FormatterBuilder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ScriptCs.WebApi
{
public class FormatterBuilder
{
private Func<Type, bool> _canReadType = t => true;
private Func<Type, bool> _canWriteType = t => true;
private Func<ReadFromStreamArgs, Task<object>> _readFromStream;
private Func<WriteToStreamArgs, Task> _writeToStream;
private readonly IList<MediaTypeMapping> _mappings;
private readonly IList<MediaTypeHeaderValue> _supportedMediaTypes;
private readonly IList<Encoding> _supportedEncodings;

public FormatterBuilder()
{
_mappings = new List<MediaTypeMapping>();
_supportedMediaTypes = new List<MediaTypeHeaderValue>();
_supportedEncodings = new List<Encoding>();
}

public FormatterBuilder CanReadType(Func<Type, bool> condition)
{
_canReadType = condition;
return this;
}

public FormatterBuilder CanWriteType(Func<Type, bool> condition)
{
_canWriteType = condition;
return this;
}

public FormatterBuilder ReadFromStream(
Func<ReadFromStreamArgs, Task<object>> readFromStream)
{
_readFromStream = readFromStream;
return this;
}

public FormatterBuilder WriteToStream(
Func<WriteToStreamArgs, Task> writeToStream)
{
_writeToStream = writeToStream;
return this;
}

public FormatterBuilder SupportMediaType(MediaTypeHeaderValue mediaType)
{
_supportedMediaTypes.Add(mediaType);
return this;
}

public FormatterBuilder SupportMediaType(string mediaType)
{
_supportedMediaTypes.Add(new MediaTypeHeaderValue(mediaType));
return this;
}

public FormatterBuilder SupportEncoding(Encoding encoding)
{
_supportedEncodings.Add(encoding);
return this;
}

public FormatterBuilder MapQueryString(
string parameterName,
string parameterValue,
MediaTypeHeaderValue mediaType)
{
_mappings.Add(new QueryStringMapping(parameterName, parameterValue, mediaType));
return this;
}

public FormatterBuilder MapQueryString(
string parameterName,
string parameterValue,
string mediaType)
{
_mappings.Add(new QueryStringMapping(parameterName, parameterValue, mediaType));
return this;
}

public FormatterBuilder MapRequestHeader(
string headerName,
string headerValue,
System.StringComparison valueComparison,
bool isValueSubstring,
string mediaType)
{
_mappings.Add(new RequestHeaderMapping(headerName, headerValue, valueComparison, isValueSubstring, mediaType));
return this;
}

public FormatterBuilder MapRequestHeader(
string headerName,
string headerValue,
System.StringComparison valueComparison,
bool isValueSubstring,
MediaTypeHeaderValue mediaType
)
{
_mappings.Add(new RequestHeaderMapping(headerName, headerValue, valueComparison, isValueSubstring, mediaType));
return this;
}

public FormatterBuilder MapUriExtension(
string extension,
string mediaType
)
{
_mappings.Add(new UriPathExtensionMapping(extension, mediaType));
return this;
}

public FormatterBuilder MapUriExtension(
string extension,
MediaTypeHeaderValue mediaType
)
{
_mappings.Add(new UriPathExtensionMapping(extension, mediaType));
return this;
}

public MediaTypeFormatter Build()
{
var formatter = new Formatter(_canReadType, _canWriteType, _readFromStream, _writeToStream);

foreach (var mediaType in _supportedMediaTypes)
{
formatter.SupportedMediaTypes.Add(mediaType);
}

foreach (var mapping in _mappings)
{
formatter.MediaTypeMappings.Add(mapping);
}

foreach (var encoding in _supportedEncodings)
{
formatter.SupportedEncodings.Add(encoding);
}

return formatter;
}
}
}
6 changes: 3 additions & 3 deletions src/ScriptCs.WebApi/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@

[assembly: Guid("be92b3c5-a23a-4234-8856-162fb14ec2b1")]

[assembly: AssemblyVersion("0.2.0")]
[assembly: AssemblyFileVersion("0.2.0")]
[assembly: AssemblyInformationalVersion("0.2.0")]
[assembly: AssemblyVersion("1.0.0")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
Loading