1
+ namespace WebApiContrib.Formatting.Razor
2
+
3
+ #if INTERACTIVE
4
+ #I " ../packages"
5
+ #r " System.Net.Http"
6
+ #r " Microsoft.AspNet.WebApi.Client.5.0.0/lib/net45/System.Net.Http.Formatting.dll"
7
+ #r " Microsoft.AspNet.WebApi.Core.5.0.0/lib/net45/System.Web.Http.dll"
8
+ #r " Microsoft.AspNet.Razor.2.0.30506.0/lib/net40/System.Web.Razor.dll"
9
+ #r " RazorEngine.3.3.0/lib/net40/RazorEngine.dll"
10
+ #r " WebApiContrib.Formatting.Html.2.0.0/lib/net45/WebApiContrib.Formatting.Html.dll"
11
+ #endif
12
+
13
+ open System
14
+ open System.IO
15
+ open System.Reflection
16
+ open RazorEngine.Configuration
17
+ open RazorEngine.Templating
18
+ open WebApiContrib.Formatting .Html
19
+ open WebApiContrib.Formatting .Html .Formatting
20
+
21
+ type RazorViewLocator () =
22
+ let viewLocationFormats =
23
+ [| " ~\\ Views\\ {0}.cshtml"
24
+ " ~\\ Views\\ {0}.vbhtml"
25
+ " ~\\ Views\\ Shared\\ {0}.cshtml"
26
+ " ~\\ Views\\ Shared\\ {0}.vbhtml" |]
27
+
28
+ static member internal GetPhysicalSiteRootPath ( siteRootPath : string ) =
29
+ if String.IsNullOrWhiteSpace( siteRootPath) then
30
+ Path.GetDirectoryName( Assembly.GetExecutingAssembly() .CodeBase)
31
+ .Replace( " file:\\ " , String.Empty)
32
+ .Replace( " \\ bin" , String.Empty)
33
+ .Replace( " \\ Debug" , String.Empty)
34
+ .Replace( " \\ Release" , String.Empty)
35
+ else siteRootPath
36
+
37
+ interface IViewLocator with
38
+ member this.GetView ( siteRootPath , view ) =
39
+ if view = Unchecked.defaultof<_> then
40
+ raise ( new ArgumentNullException( " view" ))
41
+
42
+ let path = RazorViewLocator.GetPhysicalSiteRootPath( siteRootPath)
43
+
44
+ let result = seq {
45
+ for viewLocationFormat in viewLocationFormats do
46
+ let potentialViewPathFormat = viewLocationFormat.Replace( " ~" , RazorViewLocator.GetPhysicalSiteRootPath( siteRootPath));
47
+
48
+ let viewPath = String.Format( potentialViewPathFormat, view.ViewName);
49
+
50
+ if File.Exists( viewPath) then
51
+ yield File.ReadAllText( viewPath) }
52
+
53
+ if Seq.isEmpty result then
54
+ raise ( new FileNotFoundException( String.Format( " Can't find a view with the name '{0}.cshtml' or '{0}.vbhtml in the '\\ Views' folder under path '{1}'" , view.ViewName, path)))
55
+ else Seq.head result
56
+
57
+ type TemplateResolver () =
58
+ interface ITemplateResolver with
59
+ member this.Resolve ( name ) =
60
+ //Replace the "~/" to the root path of the web.
61
+ let name = name.Replace( " ~" , RazorViewLocator.GetPhysicalSiteRootPath( null )) .Replace( " /" , " \\ " )
62
+
63
+ if not ( File.Exists( name)) then
64
+ raise ( new FileNotFoundException( name))
65
+
66
+ File.ReadAllText( name)
67
+
68
+ // Type passed should be located at the root of the folder structure where the embedded templates are located
69
+ type EmbeddedResolver ( rootLocatorType : Type ) =
70
+ interface ITemplateResolver with
71
+ member this.Resolve ( name ) =
72
+ // To locate embedded files,
73
+ // - they must be marked as "Embedded Resource"
74
+ // - you must use a case senstive path and filename
75
+ // - the namespaces and project folder names must match.
76
+ //
77
+ name = name.Replace( " ~/" , " " ) .Replace( " /" , " ." ) //Convert "web path" to "resource path"
78
+ let viewStream = rootLocatorType.Assembly.GetManifestResourceStream( rootLocatorType, name)
79
+ use reader = new StreamReader( viewStream)
80
+ reader.ReadToEnd()
81
+
82
+ /// <summary>
83
+ /// An <see cref="IViewParser"/> for Razor templates.
84
+ /// </summary>
85
+ /// <param name="templateService">The <see cref="ITemplateService"/>.</param>
86
+ type RazorViewParser ( templateService : ITemplateService ) =
87
+
88
+ do if templateService = Unchecked.defaultof<_> then
89
+ raise ( new ArgumentNullException( " templateService" ))
90
+
91
+ /// <summary>
92
+ /// Initializes a new <see cref="RazorViewParser"/> with the specified <paramref name="ITemplateServiceConfiguration"/>.
93
+ /// </summary>
94
+ /// <param name="config">The <see cref="ITemplateServiceConfiguration"/>.</param>
95
+ new ( config : ITemplateServiceConfiguration ) =
96
+ new RazorViewParser( new TemplateService( config) :> ITemplateService)
97
+
98
+ /// <summary>
99
+ /// Initializes a new <see cref="RazorViewParser"/> with optional arguments.
100
+ /// </summary>
101
+ /// <param name="resolver">The <see cref="ITemplateResolver"/>. If not provided, <see cref="TemplateResolver"/> is used.</param>
102
+ /// <param name="baseTemplateType">The <see cref="Type"/> to use as the TemplateBase.</param>
103
+ new (? resolver : ITemplateResolver , ? baseTemplateType : Type ) =
104
+ let resolver = defaultArg resolver ( new TemplateResolver() :> ITemplateResolver)
105
+ let baseTemplateType = defaultArg baseTemplateType Unchecked.defaultof<_>
106
+ let config = new TemplateServiceConfiguration( BaseTemplateType = baseTemplateType, Resolver = resolver)
107
+ new RazorViewParser( new TemplateService( config) :> ITemplateService)
108
+
109
+ interface IViewParser with
110
+ /// <summary>
111
+ /// Parses the <paramref name="viewTemplate"/> with the provided <paramref name="view"/>.
112
+ /// </summary>
113
+ /// <param name="view">The <see cref="IView"/>.</param>
114
+ /// <param name="viewTemplate">The view template to parse.</param>
115
+ /// <param name="encoding">The <see cref="System.Text.Encoding"/> to use in parsing.</param>
116
+ /// <returns>The <see cref="byte[]"/> representing the parsed view.</returns>
117
+ member this.ParseView ( view , viewTemplate , encoding ) =
118
+ templateService.Compile( viewTemplate, view.ModelType, view.ViewName)
119
+ let parsedView = templateService.Run( view.ViewName, view.Model, null )
120
+ encoding.GetBytes( parsedView);
121
+
122
+ /// <summary>
123
+ /// <see cref="HtmlMediaTypeFormatter"/> using the Razor syntax.
124
+ /// </summary>
125
+ /// <param name="siteRootPath">The root path containing view files. This defaults to "~/Views".</param>
126
+ /// <param name="viewLocator">The <see cref="IViewLocator"/> instance used to locate the correct view. This defaults to <see cref="RazorViewLocator"/>.</param>
127
+ /// <param name="viewParser">The <see cref="IViewParser"/> instance used to parse the view. This defaults to <see cref="RazorViewParser"/>.</param>
128
+ [<Sealed>]
129
+ type RazorViewFormatter (? siteRootPath : string , ? viewLocator : IViewLocator , ? viewParser : IViewParser ) =
130
+ inherit HtmlMediaTypeViewFormatter(
131
+ defaultArg siteRootPath null ,
132
+ defaultArg viewLocator ( new RazorViewLocator() :> IViewLocator),
133
+ defaultArg viewParser ( new RazorViewParser() :> IViewParser))
0 commit comments