This commit is contained in:
supernebula
2017-08-10 18:45:05 +08:00
parent de628601b2
commit 0caefef59e
17 changed files with 582 additions and 5 deletions
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace Plunder.Setting.Core.Extensions
{
public static class DictionaryExtensions
{
public static T GetValue<T>(this IDictionary<string, object> dic, string key)
{
if (dic == null)
throw new ArgumentNullException(nameof(dic));
object valueObj = null;
if (dic.TryGetValue(key, out valueObj))
{
if (valueObj is T)
return (T)valueObj;
}
return default(T);
}
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
namespace Plunder.Setting.Core.Http
{
public class HtmlActionResult : IHttpActionResult
{
private const string ViewDirectory = @"E:devConsoleApplication8ConsoleApplication8";
private readonly string _view;
private readonly dynamic _model;
private readonly HttpRequestMessage _request;
private readonly string _location;
public HtmlActionResult(string viewName, object model)
{
_view = LoadView(viewName);
_model = model;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
private static string LoadView(string name)
{
var view = File.ReadAllText(Path.Combine(ViewDirectory, name + ".cshtml"));
return view;
}
}
}
@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
namespace Plunder.Setting.Core.Mvc
{
public class Controller : ApiController
{
private ExpandoObject _viewDataDictionary;
public dynamic ViewData
{
get
{
if (_viewDataDictionary == null)
{
_viewDataDictionary = new ExpandoObject();
}
return _viewDataDictionary;
}
set { _viewDataDictionary = value; }
}
protected internal ViewResult View()
{
return View(viewName: null, masterName: null, model: null);
}
protected internal ViewResult View(object model)
{
return View(null /* viewName */, null /* masterName */, model);
}
protected internal ViewResult View(string viewName)
{
return View(viewName, masterName: null, model: null);
}
protected internal ViewResult View(string viewName, string masterName)
{
return View(viewName, masterName, null /* model */);
}
protected internal ViewResult View(string viewName, object model)
{
return View(viewName, null /* masterName */, model);
}
protected internal virtual ViewResult View(string viewName, string masterName, object model)
{
if (model != null)
{
ViewData.Model = model;
}
return new ViewResult
{
ViewName = viewName,
MasterName = masterName,
ViewData = ViewData,
TempData = TempData,
ViewEngineCollection = ViewEngineCollection
};
}
}
}
+15
View File
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
namespace Plunder.Setting.Core.Mvc
{
public interface IView
{
void Render(HttpControllerContext controllerContext, TextWriter writer);
}
}
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
namespace Plunder.Setting.Core.Mvc
{
public interface IViewEngine
{
ViewEngineResult FindPartialView(HttpControllerContext controllerContext, string partialViewName, bool useCache);
ViewEngineResult FindView(HttpControllerContext controllerContext, string viewName, string masterName, bool useCache);
void ReleaseView(HttpControllerContext controllerContext, IView view);
}
}
@@ -0,0 +1,231 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using Plunder.Setting.Core.Extensions;
using System.Globalization;
namespace Plunder.Setting.Core.Mvc
{
public class RazorViewEngine : IViewEngine
{
internal static readonly string ViewStartFileName = "_ViewStart";
private const string CacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:"; //{4}:
private const string CacheKeyPrefixMaster = "Master";
private const string CacheKeyPrefixPartial = "Partial";
private const string CacheKeyPrefixView = "View";
private static readonly string[] _emptyLocations = new string[0];
public string[] ViewLocationFormats { get; set; }
public string[] MasterLocationFormats { get; set; }
public string[] PartialViewLocationFormats { get; set; }
public string[] FileExtensions { get; set; }
public ViewEngineResult FindPartialView(HttpControllerContext controllerContext, string partialViewName, bool useCache)
{
throw new NotImplementedException();
}
public ViewEngineResult FindView(HttpControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
if (String.IsNullOrEmpty(viewName))
{
throw new ArgumentNullException("viewName");
}
string[] viewLocationsSearched;
string[] masterLocationsSearched;
string controllerName = controllerContext.RouteData.Values.GetValue<string>("controller");
string viewPath = GetPath(controllerContext, ViewLocationFormats, /*AreaViewLocationFormats,*/ "ViewLocationFormats", viewName, controllerName, CacheKeyPrefixView, out viewLocationsSearched);
string masterPath = GetPath(controllerContext, MasterLocationFormats,/* AreaMasterLocationFormats,*/ "MasterLocationFormats", masterName, controllerName, CacheKeyPrefixMaster, out masterLocationsSearched);
if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
{
return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
}
return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
}
private string GetPath(HttpControllerContext controllerContext, string[] locations, /*string[] areaLocations,*/ string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix, out string[] searchedLocations)
{
searchedLocations = _emptyLocations;
if (String.IsNullOrEmpty(name))
{
return String.Empty;
}
//string areaName = AreaHelpers.GetAreaName(controllerContext.RouteData);
//bool usingAreas = !String.IsNullOrEmpty(areaName);
List<ViewLocation> viewLocations = GetViewLocations(locations/*, (usingAreas) ? areaLocations : null*/);
if (viewLocations.Count == 0)
throw new InvalidOperationException(nameof(locations));
bool nameRepresentsPath = IsSpecificPath(name);
string cacheKey = CreateCacheKey(cacheKeyPrefix, name, (nameRepresentsPath) ? String.Empty : controllerName/*, areaName*/);
return nameRepresentsPath
? GetPathFromSpecificName(controllerContext, name, cacheKey, ref searchedLocations)
: GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName/*, areaName*/, cacheKey, ref searchedLocations);
}
private string GetPathFromGeneralName(HttpControllerContext controllerContext, List<ViewLocation> locations, string name, string controllerName, /*string areaName,*/ string cacheKey, ref string[] searchedLocations)
{
string result = String.Empty;
searchedLocations = new string[locations.Count];
for (int i = 0; i < locations.Count; i++)
{
ViewLocation location = locations[i];
string virtualPath = location.Format(name, controllerName);
DisplayInfo virtualPathDisplayInfo = DisplayModeProvider.GetDisplayInfoForVirtualPath(virtualPath, controllerContext.HttpContext, path => FileExists(controllerContext, path), controllerContext.DisplayMode);
if (virtualPathDisplayInfo != null)
{
string resolvedVirtualPath = virtualPathDisplayInfo.FilePath;
searchedLocations = _emptyLocations;
result = resolvedVirtualPath;
ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, AppendDisplayModeToCacheKey(cacheKey, virtualPathDisplayInfo.DisplayMode.DisplayModeId), result);
if (controllerContext.DisplayMode == null)
{
controllerContext.DisplayMode = virtualPathDisplayInfo.DisplayMode;
}
// Populate the cache for all other display modes. We want to cache both file system hits and misses so that we can distinguish
// in future requests whether a file's status was evicted from the cache (null value) or if the file doesn't exist (empty string).
IEnumerable<IDisplayMode> allDisplayModes = DisplayModeProvider.Modes;
foreach (IDisplayMode displayMode in allDisplayModes)
{
if (displayMode.DisplayModeId != virtualPathDisplayInfo.DisplayMode.DisplayModeId)
{
DisplayInfo displayInfoToCache = displayMode.GetDisplayInfo(controllerContext.HttpContext, virtualPath, virtualPathExists: path => FileExists(controllerContext, path));
string cacheValue = String.Empty;
if (displayInfoToCache != null && displayInfoToCache.FilePath != null)
{
cacheValue = displayInfoToCache.FilePath;
}
ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, AppendDisplayModeToCacheKey(cacheKey, displayMode.DisplayModeId), cacheValue);
}
}
break;
}
searchedLocations[i] = virtualPath;
}
return result;
}
private string GetPathFromSpecificName(HttpControllerContext controllerContext, string name, string cacheKey, ref string[] searchedLocations)
{
string result = name;
if (!(FilePathIsSupported(name) && FileExists(controllerContext, name)))
{
result = String.Empty;
searchedLocations = new[] { name };
}
ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
return result;
}
private bool FilePathIsSupported(string virtualPath)
{
if (FileExtensions == null)
{
// legacy behavior for custom ViewEngine that might not set the FileExtensions property
return true;
}
else
{
// get rid of the '.' because the FileExtensions property expects extensions withouth a dot.
string extension = GetExtensionThunk(virtualPath).TrimStart('.');
return FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
}
}
private static List<ViewLocation> GetViewLocations(string[] viewLocationFormats/*, string[] areaViewLocationFormats*/)
{
List<ViewLocation> allLocations = new List<ViewLocation>();
//if (areaViewLocationFormats != null)
//{
// foreach (string areaViewLocationFormat in areaViewLocationFormats)
// {
// allLocations.Add(new AreaAwareViewLocation(areaViewLocationFormat));
// }
//}
if (viewLocationFormats != null)
{
foreach (string viewLocationFormat in viewLocationFormats)
{
allLocations.Add(new ViewLocation(viewLocationFormat));
}
}
return allLocations;
}
internal virtual string CreateCacheKey(string prefix, string name, string controllerName/*, string areaName*/)
{
return String.Format(CultureInfo.InvariantCulture, CacheKeyFormat,
GetType().AssemblyQualifiedName, prefix, name, controllerName/*, areaName*/);
}
private static bool IsSpecificPath(string name)
{
char c = name[0];
return (c == '~' || c == '/');
}
public void ReleaseView(HttpControllerContext controllerContext, IView view)
{
throw new NotImplementedException();
}
public RazorViewEngine()
{
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
MasterLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
PartialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.cshtml",
"~/Views/Shared/{0}.cshtml"
};
FileExtensions = new[]
{
"cshtml"
};
}
}
}
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
namespace Plunder.Setting.Core.Mvc
{
public class ViewEngineResult
{
public ViewEngineResult(IEnumerable<string> searchedLocations)
{
if (searchedLocations == null)
{
throw new ArgumentNullException("searchedLocations");
}
SearchedLocations = searchedLocations;
}
public ViewEngineResult(IView view, IViewEngine viewEngine)
{
if (view == null)
{
throw new ArgumentNullException("view");
}
if (viewEngine == null)
{
throw new ArgumentNullException("viewEngine");
}
View = view;
ViewEngine = viewEngine;
}
public IEnumerable<string> SearchedLocations { get; private set; }
public IView View { get; private set; }
public IViewEngine ViewEngine { get; private set; }
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Plunder.Setting.Core.Mvc
{
internal class ViewLocation
{
protected string _virtualPathFormatString;
public ViewLocation(string virtualPathFormatString)
{
_virtualPathFormatString = virtualPathFormatString;
}
public virtual string Format(string viewName, string controllerName)
{
return String.Format(CultureInfo.InvariantCulture, _virtualPathFormatString, viewName, controllerName);
}
}
}
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
namespace Plunder.Setting.Core.Mvc
{
public class ViewResult : IHttpActionResult
{
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
}
}
}
+15 -3
View File
@@ -101,11 +101,20 @@
<Compile Include="ApiControllers\ExtractRuleController.cs" />
<Compile Include="ApiControllers\HomeController.cs" />
<Compile Include="ApiControllers\ValuesController.cs" />
<Compile Include="Core\Extensions\DictionaryExtensions.cs" />
<Compile Include="Core\Http\HtmlActionResult.cs" />
<Compile Include="Core\Mvc\Controller.cs" />
<Compile Include="Core\Mvc\IView.cs" />
<Compile Include="Core\Mvc\IViewEngine.cs" />
<Compile Include="Core\Mvc\RazorViewEngine.cs" />
<Compile Include="Core\Mvc\ViewEngineResult.cs" />
<Compile Include="Core\Mvc\ViewLocation.cs" />
<Compile Include="Core\Mvc\ViewResult.cs" />
<Compile Include="UIControllers\DomainUIController.cs" />
<Compile Include="Core\Http\Dispatcher\HttpControllerTypeCache.cs" />
<Compile Include="Core\Http\NamespaceHttpControllerSelector.cs" />
<Compile Include="Core\Http\HttpRouteCollectionExtensions.cs" />
<Compile Include="Core\Http\OldNamespaceHttpControllerSelector.cs" />
<Compile Include="Core\Http\~NamespaceHttpControllerSelector.cs" />
<Compile Include="Core\Http\~HttpRouteCollectionExtensions.cs" />
<Compile Include="Core\Http\~OldNamespaceHttpControllerSelector.cs" />
<Compile Include="Data\Interfaces\IDomainQuery.cs" />
<Compile Include="Data\Interfaces\IDomainRepository.cs" />
<Compile Include="Data\Mongo\DomainQuery.cs" />
@@ -124,6 +133,9 @@
<None Include="App.config" />
<Compile Include="App_Start\Startup.StaticFile.cs" />
<None Include="packages.config" />
<None Include="Views\HomeUI\Index.cshtml" />
<None Include="Views\Web.config" />
<None Include="Views\_ViewStart.cshtml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Infrastructure\Evol.Common\Evol.Common.csproj">
@@ -8,7 +8,7 @@ using System.Net.Http.Headers;
namespace Plunder.Setting.UIControllers
{
/// <summary>
///
/// <see cref="https://www.strathweb.com/2013/06/ihttpactionresult-new-way-of-creating-responses-in-asp-net-web-api-2/"/>
/// </summary>
[RoutePrefix("ui/Home")]
public class HomeUIController : ApiController
@@ -18,7 +18,35 @@ namespace Plunder.Setting.UIControllers
[Route("~/ui")]
[Route("~/")]
[HttpGet]
public HttpResponseMessage Index()
public IHttpActionResult Index()
{
var templateKey = "domainui.index";
string template = "Hello @Model ! This is UI! Path:" + Request.RequestUri.AbsolutePath;
//string result = RazEngine.Razor.Compile(template, new { Name = "World" });
string result = null;
if (RazEngine.Razor.IsTemplateCached(templateKey, typeof(string)))
result = RazEngine.Razor.Run(templateKey, model: "Man");
else
result = RazEngine.Razor.RunCompile(template, "templateKey", null, "Man");
var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK);
var viewPath = this.RequestContext.
httpResponseMessage.Content = new StringContent(result);
MediaTypeHeaderValue mediaTypeHeaderValue = new MediaTypeHeaderValue("text/html");
mediaTypeHeaderValue.CharSet = System.Text.Encoding.UTF8.WebName;
httpResponseMessage.Content.Headers.ContentType = mediaTypeHeaderValue;
return httpResponseMessage;
}
public HttpResponseMessage Index2()
{
var templateKey = "domainui.index";
string template = "Hello @Model ! This is UI! Path:" + Request.RequestUri.AbsolutePath;
@@ -0,0 +1,15 @@
@model string
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
</body>
</html>
+45
View File
@@ -0,0 +1,45 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Optimization"/>
<add namespace="System.Web.Routing" />
<add namespace="Mgs.MobileSite" />
<add namespace="Mgs.MobileSite.Helpers"/>
<add namespace="Mgs.Web.Mvc.Html"/>
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
<system.web>
<compilation>
<assemblies>
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
</system.web>
</configuration>
@@ -0,0 +1,3 @@
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}