--------------------------------------------------------------------------------
/src/Giraffe.Razor/Giraffe.Razor.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Giraffe.Razor
5 | Razor view engine support for the Giraffe web framework.
6 | Copyright 2020 Dustin Moris Gorski
7 | Dustin Moris Gorski and contributors
8 | en-GB
9 |
10 |
11 | $(NoWarn);NU5104
12 |
13 |
14 | net5.0
15 | portable
16 | Library
17 | true
18 | false
19 | true
20 | true
21 |
22 |
23 | Giraffe.Razor
24 | Giraffe;Razor;ASP.NET Core;Lambda;FSharp;Functional;Http;Web;Framework;Micro;Service
25 | https://raw.githubusercontent.com/giraffe-fsharp/Giraffe.Razor/master/RELEASE_NOTES.md
26 | giraffe-64x64.png
27 | https://github.com/giraffe-fsharp/Giraffe.Razor
28 | Apache-2.0
29 | true
30 | git
31 | https://github.com/giraffe-fsharp/Giraffe.Razor
32 |
33 |
34 | true
35 | true
36 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
37 | $(NoWarn);FS2003
38 |
39 |
40 |
41 |
42 | true
43 | $(PackageIconUrl)
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/Giraffe.Razor/HttpHandlers.fs:
--------------------------------------------------------------------------------
1 | namespace Giraffe.Razor
2 |
3 | []
4 | module HttpHandlers =
5 |
6 | open System.Text
7 | open System.Threading.Tasks
8 | open System.Collections.Generic
9 | open Microsoft.AspNetCore.Http
10 | open Microsoft.AspNetCore.Mvc.ModelBinding
11 | open Microsoft.AspNetCore.Mvc.Razor
12 | open Microsoft.AspNetCore.Mvc.ViewFeatures
13 | open Microsoft.Extensions.DependencyInjection
14 | open Microsoft.AspNetCore.Antiforgery
15 | open FSharp.Control.Tasks
16 | open Giraffe
17 | open RazorEngine
18 |
19 | /// Reads a razor view from disk and compiles it with the given model and sets
20 | /// the compiled output as the HTTP reponse with the given contentType.
21 | let razorView (contentType : string)
22 | (viewName : string)
23 | (model : 'T option)
24 | (viewData : IDictionary option)
25 | (modelState : ModelStateDictionary option) : HttpHandler =
26 | fun (next : HttpFunc) (ctx : HttpContext) ->
27 | task {
28 | let metadataProvider = ctx.RequestServices.GetService()
29 | let engine = ctx.RequestServices.GetService()
30 | let tempDataDict = ctx.RequestServices.GetService().GetTempData ctx
31 | let! result = renderView engine metadataProvider tempDataDict ctx viewName model viewData modelState
32 | match result with
33 | | Error msg -> return (failwith msg)
34 | | Ok output ->
35 | let bytes = Encoding.UTF8.GetBytes output
36 | return! (setHttpHeader "Content-Type" contentType >=> setBody bytes) next ctx
37 | }
38 |
39 | /// Reads a razor view from disk and compiles it with the given model and sets
40 | /// the compiled output as the HTTP reponse with a Content-Type of text/html.
41 | let razorHtmlView (viewName : string)
42 | (model : 'T option)
43 | (viewData : IDictionary option)
44 | (modelState : ModelStateDictionary option) : HttpHandler =
45 | razorView "text/html; charset=utf-8" viewName model viewData modelState
46 |
47 | /// Validates an anti forgery token.
48 | /// If the token is valid the handler will procceed as normal,
49 | /// otherwise it will execute the invalidTokenHandler.
50 | let validateAntiforgeryToken (invalidTokenHandler : HttpHandler) : HttpHandler =
51 | fun next ctx ->
52 | task {
53 | let antiforgery = ctx.GetService()
54 | let! isValid = antiforgery.IsRequestValidAsync ctx
55 | return!
56 | if isValid then next ctx
57 | else invalidTokenHandler (Some >> Task.FromResult) ctx
58 | }
--------------------------------------------------------------------------------
/RELEASE_NOTES.md:
--------------------------------------------------------------------------------
1 | Release Notes
2 | =============
3 |
4 | ## 5.1.0-rc-2
5 |
6 | - Updated `Giraffe` dependency to `5.0.0-rc-6` and changed from `TaskBuilder.fs` to `Ply` for `task` CEs.
7 |
8 | ## 5.1.0-rc-1
9 |
10 | - Upgraded to .NET 5
11 | - Added an overload to the `AddRazorEngine` extension method to set if existing file providers should be kept or cleared via the `persistFileProviders` flag.
12 |
13 | ## 5.0.0
14 |
15 | - Dropped support for all .NET framework monikers except .NET Core 3.1 (in preparation for the .NET 5 release)
16 | - Added support for `IModelMetadataProvider`
17 |
18 | ## 4.0.0
19 |
20 | #### Breaking changes & Bug fixes
21 |
22 | - Fixed a bug around the `TempData` implementation to ensure that all previously stored data in the `TempData` dictionary is accessible as well as newly made changes are persisted going forward.
23 |
24 | #### New features
25 |
26 | - Added an additional overload of `AddRazorEngine` which does not take any arguments, which supports Razor views from a class library.
27 |
28 | ## 3.0.0
29 |
30 | #### New features/Breaking changes
31 |
32 | - Added a new parameter to the `razorView`, `razorHtmlView`, and `RazorEngine.renderView` functions to support a `ModelStateDictionary`.
33 |
34 | ## 2.0.0
35 |
36 | #### New features/Breaking changes
37 |
38 | - Added support for view data in the `razorView` and `razorHtmlView` http handlers
39 |
40 | #### Improvements
41 |
42 | - Upgraded to Giraffe 3.2.*
43 | - Upgraded to latest TaskBuilder.fs
44 | - Added `charset=utf-8` to the `Content-Type` header when calling `razorHtmlView`
45 |
46 | ## 1.3.0
47 |
48 | Upgraded to Giraffe `2.0.0` and the latest ASP.NET Core `2.1.*` NuGet packages.
49 |
50 | ## 1.2.0
51 |
52 | Added support for view folders (see [#1](https://github.com/giraffe-fsharp/Giraffe.Razor/issues/1), [#3](https://github.com/giraffe-fsharp/Giraffe.Razor/issues/3)).
53 |
54 | ## 1.1.0
55 |
56 | Upgraded to Giraffe `1.1.0`.
57 |
58 | ## 1.0.1
59 |
60 | Changed copyright notice in NuGet package.
61 |
62 | ## 1.0.0
63 |
64 | Upgraded to latest Giraffe `1.0.0` release.
65 |
66 | ## 0.1.0-beta-310
67 |
68 | Upgraded to latest Giraffe `0.1.0-beta-6**` release.
69 |
70 | ## 0.1.0-beta-300
71 |
72 | Upgraded to latest Giraffe `0.1.0-beta-5**`, which has a new dependency on `Giraffe.Tasks` from NuGet.
73 |
74 | #### New features
75 |
76 | - Added `validateAntiforgeryToken` http handler for verifying anti forgery tokens.
77 |
78 | ## 0.1.0-beta-200
79 |
80 | #### Breaking changes
81 |
82 | - Renamed the `Giraffe.Razor.Engine` module to `RazorEngine` and moved it under the namespace `Giraffe.Razor`. If you were using the `renderRazorView` function to render individual razor views then you have to change the function call to `RazorEngine.renderView` now.
83 |
84 | (Most Giraffe users will probably not bet affected if they were using the `razorView` or `razorHtmlView` http handlers.)
85 |
86 | ## 0.1.0-beta-110 and before
87 |
88 | Previous releases of this library were documented in [Giraffe's release notes](https://github.com/giraffe-fsharp/Giraffe/blob/master/RELEASE_NOTES.md).
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: .NET Core
2 | on:
3 | push:
4 | pull_request:
5 | release:
6 | types:
7 | - published
8 | env:
9 | # Stop wasting time caching packages
10 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
11 | # Disable sending usage data to Microsoft
12 | DOTNET_CLI_TELEMETRY_OPTOUT: true
13 | # Project name to pack and publish
14 | PROJECT_NAME: Giraffe.Razor
15 | # GitHub Packages Feed settings
16 | GITHUB_FEED: https://nuget.pkg.github.com/giraffe-fsharp/
17 | GITHUB_USER: dustinmoris
18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
19 | # Official NuGet Feed settings
20 | NUGET_FEED: https://api.nuget.org/v3/index.json
21 | NUGET_KEY: ${{ secrets.NUGET_KEY }}
22 | jobs:
23 | build:
24 | runs-on: ${{ matrix.os }}
25 | strategy:
26 | matrix:
27 | os: [ ubuntu-latest, windows-latest, macos-latest ]
28 | steps:
29 | - name: Checkout
30 | uses: actions/checkout@v2
31 | - name: Setup .NET Core
32 | uses: actions/setup-dotnet@v1
33 | with:
34 | dotnet-version: 5.0.100
35 | - name: Restore
36 | run: dotnet restore
37 | - name: Build
38 | run: dotnet build -c Release --no-restore
39 | - name: Test
40 | run: dotnet test -c Release
41 | - name: Pack
42 | if: matrix.os == 'ubuntu-latest'
43 | run: dotnet pack -v normal -c Release --no-restore --include-symbols --include-source -p:PackageVersion=$GITHUB_RUN_ID src/$PROJECT_NAME/$PROJECT_NAME.*proj
44 | - name: Upload Artifact
45 | if: matrix.os == 'ubuntu-latest'
46 | uses: actions/upload-artifact@v2
47 | with:
48 | name: nupkg
49 | path: ./src/${{ env.PROJECT_NAME }}/bin/Release/*.nupkg
50 | prerelease:
51 | needs: build
52 | if: github.ref == 'refs/heads/develop'
53 | runs-on: ubuntu-latest
54 | steps:
55 | - name: Download Artifact
56 | uses: actions/download-artifact@v1
57 | with:
58 | name: nupkg
59 | - name: Push to GitHub Feed
60 | run: |
61 | for f in ./nupkg/*.nupkg
62 | do
63 | curl -vX PUT -u "$GITHUB_USER:$GITHUB_TOKEN" -F package=@$f $GITHUB_FEED
64 | done
65 | deploy:
66 | needs: build
67 | if: github.event_name == 'release'
68 | runs-on: ubuntu-latest
69 | steps:
70 | - uses: actions/checkout@v2
71 | - name: Setup .NET Core
72 | uses: actions/setup-dotnet@v1
73 | with:
74 | dotnet-version: 5.0.100
75 | - name: Create Release NuGet package
76 | run: |
77 | arrTag=(${GITHUB_REF//\// })
78 | VERSION="${arrTag[2]}"
79 | echo Version: $VERSION
80 | VERSION="${VERSION//v}"
81 | echo Clean Version: $VERSION
82 | dotnet pack -v normal -c Release --include-symbols --include-source -p:PackageVersion=$VERSION -o nupkg src/$PROJECT_NAME/$PROJECT_NAME.*proj
83 | - name: Push to GitHub Feed
84 | run: |
85 | for f in ./nupkg/*.nupkg
86 | do
87 | curl -vX PUT -u "$GITHUB_USER:$GITHUB_TOKEN" -F package=@$f $GITHUB_FEED
88 | done
89 | - name: Push to NuGet Feed
90 | run: dotnet nuget push ./nupkg/*.nupkg --source $NUGET_FEED --skip-duplicate --api-key $NUGET_KEY
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at giraffe@dusted.codes. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/src/Giraffe.Razor/RazorEngine.fs:
--------------------------------------------------------------------------------
1 | namespace Giraffe.Razor
2 |
3 | module RazorEngine =
4 |
5 | open System
6 | open System.IO
7 | open System.Collections.Generic
8 | open Microsoft.AspNetCore.Http
9 | open Microsoft.AspNetCore.Mvc
10 | open Microsoft.AspNetCore.Mvc.Abstractions
11 | open Microsoft.AspNetCore.Mvc.ModelBinding
12 | open Microsoft.AspNetCore.Mvc.Razor
13 | open Microsoft.AspNetCore.Mvc.Rendering
14 | open Microsoft.AspNetCore.Mvc.ViewFeatures
15 | open Microsoft.AspNetCore.Routing
16 | open FSharp.Control.Tasks
17 |
18 | let private extractRouteData (path : string) =
19 | // Normalize nulls
20 | let templatePath = path + ""
21 |
22 | // Split path into segments and reverse the orders
23 | let segments =
24 | templatePath.Split('/', '\\')
25 | |> List.ofSeq
26 | |> List.rev
27 |
28 | let routeValues =
29 | seq {
30 | for i in 1..segments.Length do
31 | match i with
32 | | 1 -> yield "action", segments.[0]
33 | | 2 -> yield "controller", segments.[1]
34 | | 3 -> yield "area", segments.[2]
35 | | x -> yield sprintf "token-%d" (x), segments.[x - 1]
36 | }
37 |
38 | // Create RouteData Object using Values Created
39 | let routeData = RouteData()
40 |
41 | for (key,value) in routeValues do
42 | routeData.Values.Add(key, value)
43 |
44 | routeData
45 |
46 | let renderView (razorViewEngine : IRazorViewEngine)
47 | (modelMetadataProvider : IModelMetadataProvider)
48 | (tempDataDict : ITempDataDictionary)
49 | (httpContext : HttpContext)
50 | (viewName : string)
51 | (model : 'T option)
52 | (viewData : IDictionary option)
53 | (modelState : ModelStateDictionary option) =
54 | task {
55 | let routeData = extractRouteData(viewName)
56 | let templateName = routeData.Values.["action"].ToString()
57 |
58 | let actionContext = ActionContext(httpContext, routeData, ActionDescriptor())
59 | let viewEngineResult = razorViewEngine.FindView(actionContext, templateName, true)
60 |
61 | match viewEngineResult.Success with
62 | | false ->
63 | let locations = String.Join(" ", viewEngineResult.SearchedLocations)
64 | return Error (sprintf "Could not find view with the name '%s'. Looked in %s." templateName locations)
65 | | true ->
66 | let view = viewEngineResult.View
67 | let viewModel = defaultArg model Unchecked.defaultof<'T>
68 | let viewModelState = defaultArg modelState (ModelStateDictionary())
69 | let viewDataDict =
70 | ViewDataDictionary<'T>(
71 | modelMetadataProvider,
72 | viewModelState,
73 | Model = viewModel)
74 | if (viewData.IsSome) then
75 | viewData.Value
76 | |> Seq.iter (fun x -> viewDataDict.Add x)
77 | let htmlHelperOptions = HtmlHelperOptions()
78 | use output = new StringWriter()
79 | let viewContext = ViewContext(actionContext, view, viewDataDict, tempDataDict, output, htmlHelperOptions)
80 | do! view.RenderAsync(viewContext)
81 | tempDataDict.Save()
82 | return Ok (output.ToString())
83 | }
--------------------------------------------------------------------------------
/Giraffe.Razor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26124.0
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{03CCBA43-B6F5-4FA7-8C18-432BB07225FC}"
7 | EndProject
8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Giraffe.Razor", "src\Giraffe.Razor\Giraffe.Razor.fsproj", "{9B52367B-CC80-452E-9062-7583995BFAC0}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E067A6B8-538E-4362-83C2-9ECBC486AC31}"
11 | EndProject
12 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "GiraffeRazorSample", "samples\GiraffeRazorSample\GiraffeRazorSample.fsproj", "{14818084-9969-4F42-8A66-394FC6670B50}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_root", "_root", "{73E09F74-F64D-4C42-92FC-19731C0C5553}"
15 | ProjectSection(SolutionItems) = preProject
16 | .gitignore = .gitignore
17 | .gitattributes = .gitattributes
18 | LICENSE = LICENSE
19 | NuGet.config = NuGet.config
20 | README.md = README.md
21 | RELEASE_NOTES.md = RELEASE_NOTES.md
22 | giraffe-64x64.png = giraffe-64x64.png
23 | CODE_OF_CONDUCT.md = CODE_OF_CONDUCT.md
24 | EndProjectSection
25 | EndProject
26 | Global
27 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
28 | Debug|Any CPU = Debug|Any CPU
29 | Debug|x64 = Debug|x64
30 | Debug|x86 = Debug|x86
31 | Release|Any CPU = Release|Any CPU
32 | Release|x64 = Release|x64
33 | Release|x86 = Release|x86
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(NestedProjects) = preSolution
39 | {9B52367B-CC80-452E-9062-7583995BFAC0} = {03CCBA43-B6F5-4FA7-8C18-432BB07225FC}
40 | {14818084-9969-4F42-8A66-394FC6670B50} = {E067A6B8-538E-4362-83C2-9ECBC486AC31}
41 | EndGlobalSection
42 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
43 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
45 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|x64.ActiveCfg = Debug|Any CPU
46 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|x64.Build.0 = Debug|Any CPU
47 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|x86.ActiveCfg = Debug|Any CPU
48 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Debug|x86.Build.0 = Debug|Any CPU
49 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
50 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Release|Any CPU.Build.0 = Release|Any CPU
51 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Release|x64.ActiveCfg = Release|Any CPU
52 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Release|x64.Build.0 = Release|Any CPU
53 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Release|x86.ActiveCfg = Release|Any CPU
54 | {9B52367B-CC80-452E-9062-7583995BFAC0}.Release|x86.Build.0 = Release|Any CPU
55 | {14818084-9969-4F42-8A66-394FC6670B50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56 | {14818084-9969-4F42-8A66-394FC6670B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
57 | {14818084-9969-4F42-8A66-394FC6670B50}.Debug|x64.ActiveCfg = Debug|Any CPU
58 | {14818084-9969-4F42-8A66-394FC6670B50}.Debug|x64.Build.0 = Debug|Any CPU
59 | {14818084-9969-4F42-8A66-394FC6670B50}.Debug|x86.ActiveCfg = Debug|Any CPU
60 | {14818084-9969-4F42-8A66-394FC6670B50}.Debug|x86.Build.0 = Debug|Any CPU
61 | {14818084-9969-4F42-8A66-394FC6670B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
62 | {14818084-9969-4F42-8A66-394FC6670B50}.Release|Any CPU.Build.0 = Release|Any CPU
63 | {14818084-9969-4F42-8A66-394FC6670B50}.Release|x64.ActiveCfg = Release|Any CPU
64 | {14818084-9969-4F42-8A66-394FC6670B50}.Release|x64.Build.0 = Release|Any CPU
65 | {14818084-9969-4F42-8A66-394FC6670B50}.Release|x86.ActiveCfg = Release|Any CPU
66 | {14818084-9969-4F42-8A66-394FC6670B50}.Release|x86.Build.0 = Release|Any CPU
67 | EndGlobalSection
68 | EndGlobal
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Giraffe.Razor
4 |
5 | Razor view engine support for the [Giraffe](https://github.com/giraffe-fsharp/Giraffe) web framework.
6 |
7 | [](https://www.nuget.org/packages/Giraffe.Razor/)
8 |
9 | ### Linux, macOS and Windows Build Status
10 |
11 | 
12 |
13 | [](https://github.com/giraffe-fsharp/Giraffe.Razor/actions?query=branch%3Adevelop++)
14 |
15 | ## Table of contents
16 |
17 | - [Documentation](#documentation)
18 | - [razorView](#razorview)
19 | - [razorHtmlView](#razorhtmlview)
20 | - [validateAntiforgeryToken](#validateantiforgerytoken)
21 | - [Samples](#samples)
22 | - [Nightly builds and NuGet feed](#nightly-builds-and-nuget-feed)
23 | - [More information](#more-information)
24 | - [License](#license)
25 |
26 | ## Documentation
27 |
28 | The `Giraffe.Razor` NuGet package adds additional `HttpHandler` functions to render Razor views in Giraffe.
29 |
30 | In order to use the Razor functionality in an (ASP.NET Core) Giraffe application you'll need to register additional dependencies through the `AddRazorEngine` extension method during application start-up:
31 |
32 | ```fsharp
33 | open Giraffe
34 | open Giraffe.Razor
35 |
36 | type Startup() =
37 | member __.ConfigureServices (svc : IServiceCollection,
38 | env : IHostingEnvironment) =
39 | let viewsFolderPath =
40 | Path.Combine(env.ContentRootPath, "Views")
41 | svc.AddRazorEngine viewsFolderPath |> ignore
42 | ```
43 |
44 | If your all of your Razor views are kept in a Razor class library, then you do not need to specify a views folder path when registering the Razor dependencies. In this case there is an overload of `AddRazorEngine` which takes no arguments:
45 |
46 | ```fsharp
47 | open Giraffe
48 | open Giraffe.Razor
49 |
50 | type Startup() =
51 | member __.ConfigureServices (svc : IServiceCollection,
52 | env : IHostingEnvironment) =
53 | svc.AddRazorEngine() |> ignore
54 | ```
55 |
56 | ### razorView
57 |
58 | The `razorView` http handler utilises the official ASP.NET Core MVC Razor view engine to compile a view into a HTML page and sets the body of the `HttpResponse` object. It requires the content type, the view name, an optional view model, an optional view data dictionary, and an optional model state dictionary as input parameters.
59 |
60 | #### Example:
61 |
62 | Use the razorView function:
63 |
64 | ```fsharp
65 | open Giraffe
66 | open Giraffe.Razor
67 |
68 | []
69 | type TestModel =
70 | {
71 | WelcomeText : string
72 | }
73 |
74 | let model = { WelcomeText = "Hello, World" }
75 |
76 | let app =
77 | choose [
78 | // Assuming there is a view called "Index.cshtml"
79 | route "/" >=> razorView "text/html" "Index" (Some model) None None
80 | ]
81 | ```
82 |
83 | ### razorHtmlView
84 |
85 | The `razorHtmlView` http handler is the same as the `razorView` handler except that it automatically sets the response's content type to `text/html; charset=utf-8`.
86 |
87 | #### Example:
88 |
89 | Use the razorView function:
90 |
91 | ```fsharp
92 | open Giraffe
93 | open Giraffe.Razor
94 | open Microsoft.AspNetCore.Mvc.ModelBinding
95 |
96 | []
97 | type TestModel =
98 | {
99 | WelcomeText : string
100 | }
101 |
102 | let model = { WelcomeText = "Hello, World" }
103 |
104 | let viewData =
105 | dict [
106 | "Title", "Hello World" :> obj
107 | "Foo", 89 :> obj
108 | "Bar", true :> obj
109 | ]
110 |
111 | let modelState = ModelStateDictionary()
112 |
113 | let app =
114 | choose [
115 | // Assuming there is a view called "Index.cshtml"
116 | route "/" >=> razorHtmlView "Index" (Some model) (Some viewData) (Some modelState)
117 | ]
118 | ```
119 |
120 | ### validateAntiforgeryToken
121 |
122 | The `validateAntiforgeryToken` http handler allows one to validate an anti forgery token created by the `Microsoft.AspNetCore.Antiforgery` API.
123 |
124 | #### Example:
125 |
126 | Inside a razor view add an anti forgery token:
127 |
128 | ```html
129 |
133 | ```
134 |
135 | Use the `validateAntiforgeryToken` function to validate the form request:
136 |
137 | ```fsharp
138 | open Giraffe
139 | open Giraffe.Razor
140 |
141 | let invalidCSRFTokenHandler = RequestErrors.badRequest "The CSRF token was invalid"
142 |
143 | let app =
144 | POST
145 | >=> route "/submit-sth"
146 | >=> validateAntiforgeryToken invalidCSRFTokenHandler
147 | >=> Successful.OK "All good"
148 | ```
149 |
150 | ## Samples
151 |
152 | Please find a fully functioning sample application under [./samples/GiraffeRazorSample/](https://github.com/giraffe-fsharp/Giraffe.Razor/tree/master/samples/GiraffeRazorSample).
153 |
154 | ## Nightly builds and NuGet feed
155 |
156 | All official release packages are published to the official and public NuGet feed.
157 |
158 | Nightly builds (builds from the `develop` branch) produce unofficial pre-release packages which can be pulled from the [project's NuGet feed on GitHub](https://github.com/orgs/giraffe-fsharp/packages).
159 |
160 | These packages are being tagged with the Workflow's run number as the package version.
161 |
162 | All other builds, such as builds triggered by pull requests produce a NuGet package which can be downloaded as an artifact from the individual GitHub action.
163 |
164 | ## More information
165 |
166 | For more information about Giraffe, how to set up a development environment, contribution guidelines and more please visit the [main documentation](https://github.com/giraffe-fsharp/Giraffe/blob/master/DOCUMENTATION.md) page.
167 |
168 | ## License
169 |
170 | [Apache 2.0](https://raw.githubusercontent.com/giraffe-fsharp/Giraffe.Razor/master/LICENSE)
--------------------------------------------------------------------------------
/samples/GiraffeRazorSample/Program.fs:
--------------------------------------------------------------------------------
1 | module GiraffeRazorSample
2 |
3 | open System
4 | open System.IO
5 | open System.Threading
6 | open Microsoft.AspNetCore
7 | open Microsoft.AspNetCore.Builder
8 | open Microsoft.AspNetCore.Hosting
9 | open Microsoft.AspNetCore.Http
10 | open Microsoft.AspNetCore.Http.Features
11 | open Microsoft.AspNetCore.Mvc.ModelBinding
12 | open Microsoft.Extensions.Logging
13 | open Microsoft.Extensions.DependencyInjection
14 | open FSharp.Control.Tasks
15 | open Giraffe
16 | open Giraffe.Razor
17 |
18 | // ---------------------------------
19 | // Models
20 | // ---------------------------------
21 |
22 | []
23 | type Person =
24 | {
25 | Name : string
26 | }
27 |
28 | []
29 | type CreatePerson =
30 | {
31 | Name : string
32 | CheckMe : bool
33 | }
34 |
35 | // ---------------------------------
36 | // Web app
37 | // ---------------------------------
38 |
39 | let antiforgeryTokenHandler =
40 | text "Bad antiforgery token"
41 | |> RequestErrors.badRequest
42 | |> validateAntiforgeryToken
43 |
44 | let bytesToKbStr (bytes : int64) =
45 | sprintf "%ikb" (bytes / 1024L)
46 |
47 | let displayFileInfos (files : IFormFileCollection) =
48 | files
49 | |> Seq.fold (fun acc file ->
50 | sprintf "%s\n\n%s\n%s" acc file.FileName (bytesToKbStr file.Length)) ""
51 | |> text
52 |
53 | let smallFileUploadHandler =
54 | fun (next : HttpFunc) (ctx : HttpContext) ->
55 | task {
56 | return!
57 | (match ctx.Request.HasFormContentType with
58 | | false -> text "Bad request" |> RequestErrors.badRequest
59 | | true -> ctx.Request.Form.Files |> displayFileInfos) next ctx
60 | }
61 |
62 | let largeFileUploadHandler =
63 | fun (next : HttpFunc) (ctx : HttpContext) ->
64 | task {
65 | let formFeature = ctx.Features.Get()
66 | let! form = formFeature.ReadFormAsync CancellationToken.None
67 | return! (form.Files |> displayFileInfos) next ctx
68 | }
69 |
70 | let renderPerson =
71 | fun (next : HttpFunc) (ctx : HttpContext) ->
72 | task {
73 | let name =
74 | match ctx.TryGetQueryStringValue "name" with
75 | | Some n -> n
76 | | None -> "Razor"
77 | let model = { Name = name }
78 | let viewData = dict [("Title", box "Mr Fox")]
79 | return! razorHtmlView "Person" (Some model) (Some viewData) None next ctx
80 | }
81 |
82 | let renderCreatePerson =
83 | let model = { Name = ""; CheckMe = true }
84 | let viewData = dict [("Title", box "Create peson")]
85 | razorHtmlView "CreatePerson" (Some model) (Some viewData) None
86 |
87 | let createPerson =
88 | fun (next : HttpFunc) (ctx : HttpContext) ->
89 | task {
90 | let modelState = ModelStateDictionary()
91 | let! model = ctx.BindModelAsync()
92 | if not model.CheckMe then
93 | modelState.AddModelError("CheckMe", "Checkbox must be checked")
94 | modelState.AddModelError(String.Empty, "Error without an associated field")
95 | if String.IsNullOrWhiteSpace(model.Name) then modelState.AddModelError("Name", "Name is rquired")
96 | if modelState.IsValid then
97 | let url = sprintf "/person?name=%s" model.Name
98 | return! redirectTo false url next ctx
99 | else
100 | let viewData = dict [("Title", box "Create peson")]
101 | return! razorHtmlView "CreatePerson" (Some model) (Some viewData) (Some modelState) next ctx
102 | }
103 |
104 | let viewData =
105 | dict [
106 | "Who", "Foo Bar" :> obj
107 | "Foo", 89 :> obj
108 | "Bar", true :> obj
109 | ]
110 |
111 | let webApp =
112 | choose [
113 | GET >=>
114 | choose [
115 | route "/" >=> text "index"
116 | route "/razor" >=> razorView "text/html" "Hello" None (Some viewData) None
117 | route "/person/create" >=> renderCreatePerson
118 | route "/person" >=> renderPerson
119 | route "/upload" >=> razorHtmlView "FileUpload" (Some "File upload") (Some viewData) None
120 | ]
121 | POST >=>
122 | choose [
123 | route "/small-upload" >=> smallFileUploadHandler
124 | route "/large-upload" >=> largeFileUploadHandler
125 | route "/person/create" >=> antiforgeryTokenHandler >=> createPerson
126 | ]
127 | text "Not Found" |> RequestErrors.notFound ]
128 |
129 | // ---------------------------------
130 | // Error handler
131 | // ---------------------------------
132 |
133 | let errorHandler (ex : Exception) (logger : ILogger) =
134 | logger.LogError(EventId(), ex, "An unhandled exception has occurred while executing the request.")
135 | clearResponse >=> ServerErrors.INTERNAL_ERROR (text ex.Message)
136 |
137 | // ---------------------------------
138 | // Main
139 | // ---------------------------------
140 |
141 | let configureApp (app : IApplicationBuilder) =
142 | app.UseGiraffeErrorHandler(errorHandler)
143 | .UseStaticFiles()
144 | .UseAuthentication()
145 | .UseGiraffe webApp
146 |
147 | let configureServices (services : IServiceCollection) =
148 | let sp = services.BuildServiceProvider()
149 | let env = sp.GetService()
150 | services.AddGiraffe() |> ignore
151 | Path.Combine(env.ContentRootPath, "Views")
152 | |> services.AddRazorEngine
153 | |> ignore
154 |
155 | let configureLogging (loggerBuilder : ILoggingBuilder) =
156 | loggerBuilder.AddFilter(fun lvl -> lvl.Equals LogLevel.Error)
157 | .AddConsole()
158 | .AddDebug() |> ignore
159 |
160 | []
161 | let main _ =
162 | let contentRoot = Directory.GetCurrentDirectory()
163 | let webRoot = Path.Combine(contentRoot, "WebRoot")
164 | WebHost.CreateDefaultBuilder()
165 | .UseWebRoot(webRoot)
166 | .Configure(Action configureApp)
167 | .ConfigureServices(configureServices)
168 | .ConfigureLogging(configureLogging)
169 | .Build()
170 | .Run()
171 | 0
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015/2017 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # Visual Studio 2017 auto generated files
33 | Generated\ Files/
34 |
35 | # MSTest test Results
36 | [Tt]est[Rr]esult*/
37 | [Bb]uild[Ll]og.*
38 |
39 | # NUNIT
40 | *.VisualState.xml
41 | TestResult.xml
42 |
43 | # Build Results of an ATL Project
44 | [Dd]ebugPS/
45 | [Rr]eleasePS/
46 | dlldata.c
47 |
48 | # Benchmark Results
49 | BenchmarkDotNet.Artifacts/
50 |
51 | # .NET Core
52 | project.lock.json
53 | project.fragment.lock.json
54 | artifacts/
55 | **/Properties/launchSettings.json
56 |
57 | # StyleCop
58 | StyleCopReport.xml
59 |
60 | # Files built by Visual Studio
61 | *_i.c
62 | *_p.c
63 | *_i.h
64 | *.ilk
65 | *.meta
66 | *.obj
67 | *.iobj
68 | *.pch
69 | *.pdb
70 | *.ipdb
71 | *.pgc
72 | *.pgd
73 | *.rsp
74 | *.sbr
75 | *.tlb
76 | *.tli
77 | *.tlh
78 | *.tmp
79 | *.tmp_proj
80 | *.log
81 | *.vspscc
82 | *.vssscc
83 | .builds
84 | *.pidb
85 | *.svclog
86 | *.scc
87 |
88 | # Chutzpah Test files
89 | _Chutzpah*
90 |
91 | # Visual C++ cache files
92 | ipch/
93 | *.aps
94 | *.ncb
95 | *.opendb
96 | *.opensdf
97 | *.sdf
98 | *.cachefile
99 | *.VC.db
100 | *.VC.VC.opendb
101 |
102 | # Visual Studio profiler
103 | *.psess
104 | *.vsp
105 | *.vspx
106 | *.sap
107 |
108 | # Visual Studio Trace Files
109 | *.e2e
110 |
111 | # TFS 2012 Local Workspace
112 | $tf/
113 |
114 | # Guidance Automation Toolkit
115 | *.gpState
116 |
117 | # ReSharper is a .NET coding add-in
118 | _ReSharper*/
119 | *.[Rr]e[Ss]harper
120 | *.DotSettings.user
121 |
122 | # JustCode is a .NET coding add-in
123 | .JustCode
124 |
125 | # TeamCity is a build add-in
126 | _TeamCity*
127 |
128 | # DotCover is a Code Coverage Tool
129 | *.dotCover
130 |
131 | # AxoCover is a Code Coverage Tool
132 | .axoCover/*
133 | !.axoCover/settings.json
134 |
135 | # Visual Studio code coverage results
136 | *.coverage
137 | *.coveragexml
138 |
139 | # NCrunch
140 | _NCrunch_*
141 | .*crunch*.local.xml
142 | nCrunchTemp_*
143 |
144 | # MightyMoose
145 | *.mm.*
146 | AutoTest.Net/
147 |
148 | # Web workbench (sass)
149 | .sass-cache/
150 |
151 | # Installshield output folder
152 | [Ee]xpress/
153 |
154 | # DocProject is a documentation generator add-in
155 | DocProject/buildhelp/
156 | DocProject/Help/*.HxT
157 | DocProject/Help/*.HxC
158 | DocProject/Help/*.hhc
159 | DocProject/Help/*.hhk
160 | DocProject/Help/*.hhp
161 | DocProject/Help/Html2
162 | DocProject/Help/html
163 |
164 | # Click-Once directory
165 | publish/
166 |
167 | # Publish Web Output
168 | *.[Pp]ublish.xml
169 | *.azurePubxml
170 | # Note: Comment the next line if you want to checkin your web deploy settings,
171 | # but database connection strings (with potential passwords) will be unencrypted
172 | *.pubxml
173 | *.publishproj
174 |
175 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
176 | # checkin your Azure Web App publish settings, but sensitive information contained
177 | # in these scripts will be unencrypted
178 | PublishScripts/
179 |
180 | # NuGet Packages
181 | *.nupkg
182 | # The packages folder can be ignored because of Package Restore
183 | **/[Pp]ackages/*
184 | # except build/, which is used as an MSBuild target.
185 | !**/[Pp]ackages/build/
186 | # Uncomment if necessary however generally it will be regenerated when needed
187 | #!**/[Pp]ackages/repositories.config
188 | # NuGet v3's project.json files produces more ignorable files
189 | *.nuget.props
190 | *.nuget.targets
191 |
192 | # Microsoft Azure Build Output
193 | csx/
194 | *.build.csdef
195 |
196 | # Microsoft Azure Emulator
197 | ecf/
198 | rcf/
199 |
200 | # Windows Store app package directories and files
201 | AppPackages/
202 | BundleArtifacts/
203 | Package.StoreAssociation.xml
204 | _pkginfo.txt
205 | *.appx
206 |
207 | # Visual Studio cache files
208 | # files ending in .cache can be ignored
209 | *.[Cc]ache
210 | # but keep track of directories ending in .cache
211 | !*.[Cc]ache/
212 |
213 | # Others
214 | ClientBin/
215 | ~$*
216 | *~
217 | *.dbmdl
218 | *.dbproj.schemaview
219 | *.jfm
220 | *.pfx
221 | *.publishsettings
222 | orleans.codegen.cs
223 |
224 | # Including strong name files can present a security risk
225 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
226 | #*.snk
227 |
228 | # Since there are multiple workflows, uncomment next line to ignore bower_components
229 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
230 | #bower_components/
231 |
232 | # RIA/Silverlight projects
233 | Generated_Code/
234 |
235 | # Backup & report files from converting an old project file
236 | # to a newer Visual Studio version. Backup files are not needed,
237 | # because we have git ;-)
238 | _UpgradeReport_Files/
239 | Backup*/
240 | UpgradeLog*.XML
241 | UpgradeLog*.htm
242 | ServiceFabricBackup/
243 | *.rptproj.bak
244 |
245 | # SQL Server files
246 | *.mdf
247 | *.ldf
248 | *.ndf
249 |
250 | # Business Intelligence projects
251 | *.rdl.data
252 | *.bim.layout
253 | *.bim_*.settings
254 | *.rptproj.rsuser
255 |
256 | # Microsoft Fakes
257 | FakesAssemblies/
258 |
259 | # GhostDoc plugin setting file
260 | *.GhostDoc.xml
261 |
262 | # Node.js Tools for Visual Studio
263 | .ntvs_analysis.dat
264 | node_modules/
265 |
266 | # Visual Studio 6 build log
267 | *.plg
268 |
269 | # Visual Studio 6 workspace options file
270 | *.opt
271 |
272 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
273 | *.vbw
274 |
275 | # Visual Studio LightSwitch build output
276 | **/*.HTMLClient/GeneratedArtifacts
277 | **/*.DesktopClient/GeneratedArtifacts
278 | **/*.DesktopClient/ModelManifest.xml
279 | **/*.Server/GeneratedArtifacts
280 | **/*.Server/ModelManifest.xml
281 | _Pvt_Extensions
282 |
283 | # Paket dependency manager
284 | .paket/paket.exe
285 | paket-files/
286 |
287 | # FAKE - F# Make
288 | .fake/
289 |
290 | # JetBrains Rider
291 | .idea/
292 | *.sln.iml
293 |
294 | # CodeRush
295 | .cr/
296 |
297 | # Python Tools for Visual Studio (PTVS)
298 | __pycache__/
299 | *.pyc
300 |
301 | # Cake - Uncomment if you are using it
302 | # tools/**
303 | # !tools/packages.config
304 |
305 | # Tabs Studio
306 | *.tss
307 |
308 | # Telerik's JustMock configuration file
309 | *.jmconfig
310 |
311 | # BizTalk build output
312 | *.btp.cs
313 | *.btm.cs
314 | *.odx.cs
315 | *.xsd.cs
316 |
317 | # OpenCover UI analysis results
318 | OpenCover/
319 |
320 | # Azure Stream Analytics local run output
321 | ASALocalRun/
322 |
323 | # MSBuild Binary and Structured Log
324 | *.binlog
325 |
326 | # NVidia Nsight GPU debugger configuration file
327 | *.nvuser
328 |
329 | # MFractors (Xamarin productivity tool) working folder
330 | .mfractor/
331 |
332 | # macOS
333 | .DS_Store
334 |
335 | # Ionide
336 | .ionide/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------