Skip to content

Commit

Permalink
Tests, cleanup, fixes, documentation (intellifactory#5)
Browse files Browse the repository at this point in the history
* Added ANC test project (they throw runtime error)

* Basic working tests

* WIP

* Added unittest project + WIP

* WIP

* Sitelet.Protect fix

* WIP

* Unit test WIP

* Changed Router.Shift (working) + updated unit tests

* Added infer tests

* Added Sitelet.Sum tests (not working because of Sitelet.Shift)

* Removed ToQuery/ToForm + IHttpContext WIP

* Removed System.Uri usage + added IHttpRequest

* IHttpRequest changes

* Small fix in shift

* Fixed HttpRequest.Form wrapping

* add HelloWorld integration test

* Removed some unnecessary comments + updated test (json test is WIP)

* Added json api testing

* Removed FSharp.SystemTextJson dependency from Sitelets

* Added test categories to unittests

* Added Sitelet.EmbedInUnion test

* Added Sitelet.InferPartialInUnion test

* Added Sitelet.Folder test and Sitelet.Empty draft (not sure if it is needed at all)

* Added Sitelet.New test

* Added Sitelet.Box/Unbox test

* Added Sitelet.Map test

* Added categories to integration test cases

* Added template for remaining sitelet tests

* Added JsonOptions to serializer

* Added Sitelet.TryMap test

* Json routing without thread blocking

* Remove all Obsoleted API

* Changed Sitelet.Protect logic, added authentication to the FSharp test project + added Sitelet.Protect test

* Removed Sitelet.Protect test template from unit tests

* Added Sitelet.InferPartial test + Sitelet.InferWithCustomErrors draft

* Added Sitelet.Embed test

* get rid of more System.Uri

* Added WS.Web.Tests + WS.Sitelets.Tests, WIP

* Removed migrated test project from solution, tests WIP

* Removed for real (didn't save on earlier commit)

* Readme WIP

* Readme updated

* CSharp tests updated

* Readme updated

Co-authored-by: András Jankó <[email protected]>
  • Loading branch information
btamas2000 and Jand42 authored Sep 3, 2021
1 parent 41e96d2 commit c2c3ca1
Show file tree
Hide file tree
Showing 145 changed files with 84,232 additions and 209 deletions.
153 changes: 153 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,154 @@
# IntelliFactory.Sitelets

`Sitelets` is an F#-based library, that provides abstractions for creating ASP.NET Core web applications.

## Table of contents

* [Installing](#installing)
* [Using Sitelets](#using-sitelets)
* [Working with other ANC web frameworks](#working-with-other-anc-web-frameworks)
* [Contributing](#contributing)

## Installing

The easiest way to add Sitelets to your project is by using dotnet cli:

```
dotnet add YOUR_PROJECTFILE package Sitelets
```

or if you work in Visual Studio, search for Sitelets in Nuget and install it in your project!

## Using Sitelets

For example let's create an ASP.NET Core Mvc app and plug Sitelets into it to make a Hello World site:

```
dotnet new mvc -lang f# -o MyMvcApp
dotnet add MyMvcApp/MyMvcApp.fsproj package Sitelets
```

For clarity, let's add a `MySitelets` folder in to project and create a `HelloWorld.fs` source file in it. Now for this site we only want to print the 'Hello World' text onto the page, only this much code will do the job:

```fsharp
module Hello
open Sitelets
type EndPoint =
| HelloEndPoint
let helloWorldSite = Sitelet.Content "/hello" EndPoint.HelloEndPoint (fun _ -> box "Hello World")
```

We also have to plug the sitelet into the application pipeline. Go to `Startup.fs` and do this:

```fsharp
...
app.UseAuthorization() |> ignore
// plug sitelet in here for example
app.UseSitelets(Hello.helloWorldSite) |> ignore
app.UseEndpoints(fun endpoints ->
...
```

After a quick build and run, if you go to the `/hello` endpoint, you will see "Hello World" in the response. Now this example only shows how easy it is to grab the package and use it in project. Here's a glimpse of what makes Sitelets a powerful tool:

```fsharp
type Pizza =
{
Customer: string
Size: int
}
type EndPoint =
| [<Method "GET"; EndPoint "/index">] Home
| [<Method "GET"; EndPoint "/greet"; Query "firstname"; Query "lastname">] GreetPerson of firstname:string * lastname: string
| [<Method "POST"; EndPoint "/order">; Json "pizza"] Order of pizza:Pizza
let inferSitelet =
Sitelet.Infer (fun ctx -> function
| Home -> // some content
| GreetPerson f l ->
// example content with the query parameters
sprintf "Hello %s %s" f l
|> box
// e.g /greet?firstname=John&lastname=Doe -> Hello John Doe
| Order p -> // same as above but json comes in request body
)
```

Please check the [documentation]() for more information.

## Working with other ANC web frameworks

Sitelets is a layer of abstraction on top of ASP.NET Core so it can work with other F# web frameworks like Giraffe or Saturn for example. Let's take a look at a Giraffe app, for starters:

```
dotnet new giraffe -o MyGiraffeApp
dotnet add MyGiraffeApp/MyGiraffeApp.fsproj package Sitelets
```

Let's add a sitelet that echoes what you write after the `/echo` endpoint

```fsharp
// ---------------------------------
// Sitelet
// ---------------------------------
type Endpoint =
| [<EndPoint "GET /echo">] Str of string
let inferredSite =
Sitelet.Infer (fun ctx -> function
| Str str -> box str
)
...
let webApp =
choose [
GET >=>
choose [
route "/" >=> indexHandler "world"
routef "/hello/%s" indexHandler
]
SiteletHelper.sitelet inferredSite
setStatusCode 404 >=> text "Not Found" ]
```

Add the sitelet to the pipeline and we are done!

## Sitelets in C#

Although the focus is on the F# side, you can also use the Sitelets library in C# ASP.NET Core project. As an example:

```cs
public class TestSitelet
{
public static Sitelet<object> S =>
new SiteletBuilder()
.With("/hello", ctx =>
"Hello World from C#"
)
.Install();
}
```

## Contributing

If you find any faults, please [submit a ticket](https://github.com/intellifactory/sitelets/issues/4).

It is an open source project so anyone is more than welcome to contribute but make sure to discuss the changes before opening a PR, otherwise it might get rejected.

## Links

* [Nuget](#TODO)
* [Intellifactory](https://intellifactory.com/)
11 changes: 11 additions & 0 deletions Sitelets.Test/ANCCSharp/ANCCSharp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Sitelets\Sitelets.fsproj" />
</ItemGroup>

</Project>
38 changes: 38 additions & 0 deletions Sitelets.Test/ANCCSharp/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using ANCCSharp.Models;
using Sitelets;

namespace ANCCSharp.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;

public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}

public IActionResult Index()
{
return View();
}

public IActionResult Privacy()
{
return View();
}

[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
11 changes: 11 additions & 0 deletions Sitelets.Test/ANCCSharp/Models/ErrorViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace ANCCSharp.Models
{
public class ErrorViewModel
{
public string RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}
26 changes: 26 additions & 0 deletions Sitelets.Test/ANCCSharp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace ANCCSharp
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
28 changes: 28 additions & 0 deletions Sitelets.Test/ANCCSharp/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:10987",
"sslPort": 44385
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ANCCSharp": {
"commandName": "Project",
"dotnetRunMessages": "true",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
58 changes: 58 additions & 0 deletions Sitelets.Test/ANCCSharp/Sitelets/TestSitelet.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Sitelets;

namespace ANCCSharp.SiteletsTest
{
[EndPoint("{first}/{last}")]
public class Name
{
public string first;
public string last;
}

[EndPoint("/person/{name}/{age}", "/person/{age}/{name}")]
public class Person
{
public Name name;
public int age;
}

[Method("GET"), EndPoint("qperson/{name}")]
public class QueryPerson
{
public QueryName name;

[Query]
public int? age;
}

public class QueryName
{
[Query]
public string first;

[Query]
public string last;
}

public class TestSitelet
{
public static Sitelet<object> S =>
new SiteletBuilder()
.With("/hello", ctx =>
"Hello World from C#"
)
.With<Person>((ctx, person) =>
String.Format("<p>{0} {1} is {2} years old.</p>", person.name.first, person.name.last, person.age)
)
.With<QueryPerson>((ctx, person) =>
person.age.HasValue ?
String.Format("<p>{0} {1} is {2} years old.</p>", person.name.first, person.name.last, person.age.Value) :
String.Format("<p>{0} {1} won't tell their age.</p>", person.name.first, person.name.last)
)
.Install();
}
}
60 changes: 60 additions & 0 deletions Sitelets.Test/ANCCSharp/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Sitelets;

namespace ANCCSharp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseSitelets<object>(SiteletsTest.TestSitelet.S);

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Loading

0 comments on commit c2c3ca1

Please sign in to comment.