How does MVC 6 renders a view. What's the actual method in Razor ViewEngine that generates the html output? Also if possible please explain the process of rendering a view.
May be you could point me to a file on mvc source on github. thanks!
Here is a complete solution of what you are looking for. I used dependency injection to get the HtmlHelper in the controller. You can inject your own helper if you want too.
using Microsoft.AspNet.Html.Abstractions;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.WebEncoders;
using System.ComponentModel.DataAnnotations;
using System;
public class MyController : Controller
{
private readonly IHtmlGenerator htmlGenerator;
ICompositeViewEngine viewEngine;
IModelMetadataProvider metadataProvider;
private readonly IHtmlHelper helper;
IHtmlEncoder htmlEncoder;
IUrlEncoder urlEncoder;
IJavaScriptStringEncoder javaScriptStringEncoder;
public MyController(IHtmlHelper helper, IHtmlGenerator htmlGenerator, ICompositeViewEngine viewEngine, IModelMetadataProvider metadataProvider, IHtmlEncoder htmlEncoder, IUrlEncoder urlEncoder, IJavaScriptStringEncoder javaScriptStringEncoder)
{
this.htmlGenerator = htmlGenerator;
this.viewEngine = viewEngine;
this.metadataProvider = metadataProvider;
this.htmlEncoder = htmlEncoder;
this.urlEncoder = urlEncoder;
this.javaScriptStringEncoder = javaScriptStringEncoder;
this.helper = helper;
}
[HttpGet]
public IActionResult MyHtmlGenerator()
{
MyViewModel temp = new MyViewModel();
var options = new HtmlHelperOptions();
options.ClientValidationEnabled = true;
ViewDataDictionary<MyViewModel> dic = new ViewDataDictionary<MyViewModel>(this.metadataProvider, new ModelStateDictionary());
ViewContext cc = new ViewContext(ActionContext, new FakeView(), dic, TempData, TextWriter.Null, options);
var type = typeof(MyViewModel);
var metadata = this.metadataProvider.GetMetadataForType(type);
ModelExplorer modelEx = new ModelExplorer(this.metadataProvider, metadata, temp);
ViewData["Description"] = "test desc";
ViewData["Id"] = 1;
this.ViewData = new ViewDataDictionary(this.metadataProvider, new ModelStateDictionary());
IHtmlHelper<MyViewModel> dd = new HtmlHelper<MyViewModel>(this.htmlGenerator, this.viewEngine, this.metadataProvider, this.htmlEncoder, this.urlEncoder, this.javaScriptStringEncoder);
((ICanHasViewContext)dd).Contextualize(cc);
dd.ViewContext.ViewData = this.ViewData;
var desc = GetString(dd.TextBoxFor(m => m.ID));
var ID = GetString(dd.TextBoxFor(m => m.Description));
// Do whatever you want with the ID and desc
return new ContentResult() { Content = ID + desc };
}
public static string GetString(IHtmlContent content)
{
var writer = new System.IO.StringWriter();
content.WriteTo(writer, new HtmlEncoder());
return writer.ToString();
}
}
public class MyViewModel : BaseAssetViewModel
{
// [RegularExpression(#"^-?\d{1,13}(\.\d{0,5})?$|^-?\.\d{1,5}$")]
[Required]
public int ID { get; set; }
[MinLength(2)]
public string Description { get; set; }
// Property with no validation
public string Other { get; set; }
}
public class FakeView : IView
{
string IView.Path
{
get
{
throw new NotImplementedException();
}
}
public Task RenderAsync(ViewContext viewContext)
{
throw new InvalidOperationException();
}
Task IView.RenderAsync(ViewContext context)
{
throw new NotImplementedException();
}
}
I don't know if this may be of help, may be you have to start to look at tag helpers:
https://github.com/DamianEdwards/TagHelperStarterWeb
they're working to a different way to create helpers that integrate in the page in a more natural way.
Related
I have a base class on baseviewmodel.
I'm facing navigationservice implemented on 6.2 on debug shows problem navigating to another viewmodel.
debug shows userdialogs break.
Is there a problem using base class in this way with those parameters . anyone faced this kind of issue
public BaseViewModel(IMvxNavigationService navigationService,
ILoginService loginService,
UserDialogs userDialogs, IValidator validator) {
_navigationService = navigationService;
_loginService = loginService;
_userDialogs = userDialogs;
_validator = validator;
Title = TextSource.GetText(StringResourceKeys.Title);
IsBusyMessage = Resources.Strings.LoadingMesssage;
}
using gettext provider like this
public class ResourcexTextProvider : IMvxTextProvider
{
private readonly ResourceManager _resourceManager;
public ResourcexTextProvider(ResourceManager resourceManager)
{
_resourceManager = resourceManager;
CurrentLanguage = CultureInfo.CurrentUICulture;
}
public CultureInfo CurrentLanguage { get; set; }
public string GetText(string namespaceKey, string typeKey, string name)
{
string resolvedKey = name;
if (!string.IsNullOrEmpty(typeKey))
{
resolvedKey = $"{typeKey}.{resolvedKey}";
}
if (!string.IsNullOrEmpty(namespaceKey))
{
resolvedKey = $"{namespaceKey}.{resolvedKey}";
}
return _resourceManager.GetString(resolvedKey, CurrentLanguage);
}
public string GetText(string namespaceKey, string typeKey, string name, params object[] formatArgs)
{
string baseText = GetText(namespaceKey, typeKey, name);
if (string.IsNullOrEmpty(baseText))
{
return baseText;
}
return string.Format(baseText, formatArgs);
}
public bool TryGetText(out string textValue, string namespaceKey, string typeKey, string name)
{
throw new System.NotImplementedException();
}
public bool TryGetText(out string textValue, string namespaceKey, string typeKey, string name, params object[] formatArgs)
{
throw new System.NotImplementedException();
}
}
}
You're trying to inject UserDialogs userDialogs in the ctor of your BaseViewModel. My guess is that you missed registering the userDialogs.
First of all you should inject interfaces instead of implementations to improve maintainability:
Mvx.IocConstruct.RegisterType<IUserDialogs, UserDialogs>();
And if my guess is correct and you are using Acr.UserDialogs you should initialize it and register it as:
Mvx.IoCProvider.RegisterSingleton<IUserDialogs>(() => UserDialogs.Instance);
Then you can inject it in any ViewModel directly using the interface:
public BaseViewModel(IMvxNavigationService navigationService,
ILoginService loginService,
IUserDialogs userDialogs,
IValidator validator) {
_navigationService = navigationService;
_loginService = loginService;
_userDialogs = userDialogs;
_validator = validator;
Title = TextSource.GetText(StringResourceKeys.Title);
IsBusyMessage = Resources.Strings.LoadingMesssage;
}
HIH
public async override void OnActivityCreated (Bundle savedInstanceState)
{
base.OnActivityCreated (savedInstanceState);
lst = View.FindViewById<ListView> (Resource.Id.lstHome);
var result = await json.GetStringbyJson ("https://api-v2.soundcloud.com/explore/Popular+Music?tag=out-of-experiment&limit=20&linked_partitioning=1");
if (result != null)
{
var items = Newtonsoft.Json.JsonConvert.DeserializeObject<TrackModel.RootObject> (result);
lst.Adapter = new TrackAdapter(Activity, items.tracks);
}
}
public class TrackAdapter:BaseAdapter
{
LayoutInflater _inflater;
List<TrackModel.Track> _tracks;
public TrackAdapter(Context context, List<TrackModel.Track> tracks)
{
_inflater=LayoutInflater.FromContext(context);
_tracks=tracks;
}
public override TrackModel.Track this[int index]
{
get{ return _tracks [index]; }
}
public override int Count{
get{ return _tracks.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView,ViewGroup parent)
{
View view = convertView ?? _inflater.Inflate (Resource.Layout.ExploreFragment, parent, false);
var track = _tracks [position];
var viewHolder = view.Tag as TrackViewHolder;
if (viewHolder == null) {
viewHolder.Title = view.FindViewById<TextView> (Resource.Id.textviewItems);
viewHolder.SubTitle = view.FindViewById<TextView> (Resource.Id.textviewSubItem);
viewHolder.Image = view.FindViewById<ImageView> (Resource.Id.image);
view.Tag = viewHolder;
}
viewHolder.Title.Text = track.title;
viewHolder.SubTitle.Text = track.track_type;
Android.Net.Uri uri = Android.Net.Uri.Parse (track.artwork_url);
viewHolder.Image.SetImageURI(uri);
return view;
}
}
public class TrackViewHolder:Java.Lang.Object
{
public TextView Title{ get; set;}
public TextView SubTitle{get;set;}
public ImageView Image{ get; set;}
}
public override TrackModel.Track this[int index]. It get a error is makred as an overdie but no suitable indexer found to overide.
I want to take data from json up listview on xamarin android.
If it is unviersal app then it easy to use.
The way you want to set the adapter for your listview will not work that way.
Setting the adapter property of the listview inside the foreach loop is totally wrong. The same applies to your textviews.
You need to implement a custom adapter that loads a layout for each of your track list item. Your custom adapter could look like the following example I've written out of my mind with out further testing. But it implements the required methods a custom adapter needs to implement.
The important part is the GetView method that returns your track layout every time the listview ask for a new item to represent. To keep the app memory down it uses the ViewHolder pattern, which isn't required if you want to use the RecycleView.
public class TrackAdapter : BaseAdapter<Tracks>
{
LayoutInflater _inflater;
List<Tracks> _tracks;
public TrackAdapter(Context context, List<Tracks) tracks)
{
_inflater = LayoutInflater.FromContext(context);
_tracks = tracks;
}
public override Tracks this [int index]
{
get { return _tracks[index]; }
}
public override int Count
{
get { return _tracks.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView ?? _inflater.Inflate(Resource.Layout.TrackListItem, parent, false);
var track = _tracks[position];
var viewHolder = view.Tag as TrackViewHolder;
if (viewHolder == null)
{
viewHolder = new TrackViewHolder();
viewHolder.Title = view.FindViewById<TextView>(Resource.Id.textviewItems);
viewHolder.Subtitle = view.FindViewById<TextView>(Resource.Id.textviewSubItems);
viewHolder.Image = view.FindViewById<ImageView>(Resource.Id.image);
view.Tag = viewHolder;
}
viewHolder.Title.Text = track.title;
viewHolder.SubTitle.Text = track.track_type;
viewHolder.Image.SetImageURI(Uri(track.artwork_url));
return view;
}
class TrackViewHolder : Java.Lang.Object
{
public TextView Title { get; set; }
public TextView SubTitle { get; set; }
public ImageView Image { get; set; }
}
}
The layout will contain your title, subtitle and image and could easily build with a normal layout file.
In your fragment you then create a new instance for TrackAdapter pass the context and the list of tracks you want to be shown in the listview.
public override void OnActivityCreated (Bundle savedInstanceState)
{
base.OnActivityCreated (savedInstanceState);
lst = View.FindViewById<ListView> (Resource.Id.lstHome);
var result = json.GetStringbyJson ("https://api-v2.soundcloud.com/explore/Popular+Music?tag=out-of-experiment&limit=20&linked_partitioning=1");
if (result != null)
{
var items = JsonConvert.DeserializeObject<TrackModel.RootObject> (result);
lst.Adapter = new TrackAdapter(Activity, items.tracks);
}
}
MVC6 introduces Tag Helpers which is a better way compared to using #Html.EditorFor, etc. However I have not found any Tag Helper that would be an alternative to #Html.DisplayFor.
Of course I can use a variable directly on a Razor page, such as #Model.BookingCode. But this does not allow to control formatting.
With MVC6, what's conceptually correct way for displaying a value of a model property?
#Html.DisplayFor still exists and can still be used.
The difference between HtmlHelpers and TagHelpers is that HtmlHelpers choose which html elements to render for you whereas TagHelpers work with html tags that you add yourself so you have more full control over what html element is used. You do have some control over the markup using templates with HtmlHelpers but you have more control with TagHelpers.
So you should think in terms of what html markup do I want to wrap this model property in and add that markup around the property itself using #Model.Property with some markup around it or continue using DisplayFor if you prefer to let the helper decide.
You can create your own tag helper
namespace MyDemo.TagHelpers
{
[HtmlTargetElement("p", Attributes = ForAttributeName)]
public class DisplayForTagHelper : TagHelper
{
private const string ForAttributeName = "asp-for";
[HtmlAttributeName(ForAttributeName)]
public ModelExpression For { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
var text = For.ModelExplorer.GetSimpleDisplayText();
output.Content.SetContent(text);
}
}
}
Add use it in view:
<p asp-for="MyProperty" class="form-control-static"></p>
I have been using this as a display tag helper.
[HtmlTargetElement("*", Attributes = ForAttributeName)]
public class DisplayForTagHelper : TagHelper
{
private const string ForAttributeName = "asp-display-for";
private readonly IHtmlHelper _html;
public DisplayForTagHelper(IHtmlHelper html)
{
_html = html;
}
[HtmlAttributeName(ForAttributeName)]
public ModelExpression Expression { get; set; }
public IHtmlHelper Html
{
get
{
(_html as IViewContextAware)?.Contextualize(ViewContext);
return _html;
}
}
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
if (output == null)
throw new ArgumentNullException(nameof(output));
var type = Expression.Metadata.UnderlyingOrModelType;
if (type.IsPrimitive)
{
output.Content.SetContent(Expression.ModelExplorer.GetSimpleDisplayText());
}
// Special Case for Personal Use
else if (typeof(Dictionary<string, string>).IsAssignableFrom(type))
{
output.Content.SetHtmlContent(Html?.Partial("Dictionary", Expression.ModelExplorer.Model));
}
else
{
var htmlContent = Html.GetHtmlContent(Expression);
output.Content.SetHtmlContent(htmlContent);
}
}
}
public static class ModelExpressionExtensions
{
public static IHtmlContent GetHtmlContent(this IHtmlHelper html, ModelExpression expression)
{
var ViewEngine = html.ViewContext.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
var BufferScope = html.GetFieldValue<IViewBufferScope>();
var htmlContent = new TemplateBuilder(ViewEngine, BufferScope, html.ViewContext, html.ViewContext.ViewData, expression.ModelExplorer, expression.Name, null, true, null).Build();
return htmlContent;
}
public static TValue GetFieldValue<TValue>(this object instance)
{
var type = instance.GetType();
var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType));
return (TValue)field?.GetValue(instance);
}
}
try below code
public class movie
{
public int ID { get; set; }
[DisplayName("Movie Title")]
public string Title { get; set; }
}
///////////////////////////////////////////////////
#model IEnumerable<MvcMovie.Models.Movie>
<h1>Show List Movies</h1>
<label asp-for="ToList()[0].Title">< /label>
#foreach (var movie in Model)
{
#movie.Title
}
I am using view model to display a dropdownlist and i am also trying to get the value of the selected list, here is my view model
public class CreateJobViewModel
{
public int[] SelectedIndustriesIds { get; set; }
public IList<SelectListItem> IndustriesList { get; set; }
}
My controller
public ActionResult Create()
{
var industryList = repository.GetAllIndustries();
var model = new CreateJobViewModel
{
IndustriesList = industryList.Select(i => new SelectListItem
{
Value = i.IndustryId.ToString(),
Text = i.Name
}).ToList()
};
return View("~/Views/Dashboard/Job/Create.cshtml", model);
}
My post controller
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateJobViewModel model)
{
try
{
var job = new Job()
{
Title = "hi",
EmploymentHourId = 1,
LocationId = 1,
Salary = 50,
SalaryPeriodId = 1,
PostCode = 2131,
Role = "world",
Description = "hello",
IsPublished = false,
ShiftId = 1,
WorkDayId = 1,
NumberOfPosition = 5,
Meal = false,
SecondYearVisa = true,
Sponsorship = true,
Accommodation = true,
DurationId = 1,
IndustryExperiencePeriod = 5,
Id = User.Identity.GetUserId(),
};
foreach (int id in model.SelectedIndustriesIds)
{
var industry = repository.Industry(id);
job.Industries.Add(industry);
}
foreach (int id in model.SelectedSpecialRequirementsId)
{
var special = repository.SpecialRequirement(id);
job.SpecialRequirements.Add(special);
}
repository.AddJob(job);
return RedirectToAction("Create");
}
catch
{
return View("~/Views/Dashboard/Job/Create.cshtml");
}
}
Every time i try to submit the selected value, i get Object reference not set to an instance of an object Error on the following line in my view:
#model Taw.WebUI.Models.CreateJobViewModel
#Html.ListBoxFor(m => m.SelectedIndustriesIds, Model.IndustriesList) -- here i get the error
Any reason why?
When you submit the form your throwing an exception (confirmed in the comments) and in the catch block you are returning the view, which throws the exception you are seeing because Model.IndustriesList is null. You need to re-assign the value before you return the view.
Since you need to assign SelectLists in the GET method and in the POST method if you return the view, I tend to re-factor this to a separate method to keep the controller code a bit cleaner. Note the following code is based on your model property being public SelectList IndustriesList { get; set; } which is a bit simpler than building IList<SelectListItem>
private void ConfigureViewModel(CreateJobViewModel model)
{
var industryList = repository.GetAllIndustries();
model.IndustriesList = new SelectList(industryList, "IndustryId", "Name")
// any other common stuff
}
and then in the action methods
public ActionResult Create()
{
var model = new CreateJobViewModel();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Create(CreateJobViewModel model)
{
try
{
....
}
catch
{
ConfigureViewModel(model);
return View(model);
}
}
Note its also good practice to test if the model is valid before attempting to save it
public ActionResult Create(CreateJobViewModel model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model); // return the view so the user can correct validation errors
}
....
I've got master page in my project, which contains some information about site copyright and some contact info in it. I'd like to take it out of master page and place it in a static files (for some reason, these files must be placed in ~/Content folder). Is there a way that I can tell in my view something like
<% Html.Include("~/Content/snippet.html") %> // not a real code
?
You are better off using a partial view (even if it only contains static text) and include it with the Html.Partial helper. But if you insist:
<%= File.ReadAllText(Server.MapPath("~/Content/snippet.html")) %>
If you are in .Net MVC 5 and want to include a HTML file a partial file without having Razor that render it:
#Html.Raw(File.ReadAllText(Server.MapPath("~/Views/Shared/ICanHaz.html")))
Use your own view engine
using
#Html.Partial("_CommonHtmlHead")
as
/Views/Shared/_CommonHtmlHead.html
or
/Views/MyArea/Shared/_CommonHtmlHead.htm
is the best for me.
Creating your own view engine for this by using the System.Web.Mvc.VirtualPathProviderViewEngine ascending class seems to be relatively easy:
/// <summary>
/// Simple render engine to load static HTML files, supposing that view files has the html/htm extension, supporting replacing tilda paths (~/MyRelativePath) in the content
/// </summary>
public class HtmlStaticViewEngine : VirtualPathProviderViewEngine
{
private static readonly ILog _log = LogManager.GetLogger(typeof (HtmlStaticViewEngine));
protected readonly DateTime? AbsoluteTimeout;
protected readonly TimeSpan? SlidingTimeout;
protected readonly CacheItemPriority? Priority;
private readonly bool _useCache;
public HtmlStaticViewEngine(TimeSpan? slidingTimeout = null, DateTime? absoluteTimeout = null, CacheItemPriority? priority = null)
{
_useCache = absoluteTimeout.HasValue || slidingTimeout.HasValue || priority.HasValue;
SlidingTimeout = slidingTimeout;
AbsoluteTimeout = absoluteTimeout;
Priority = priority;
AreaViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.html",
"~/Areas/{2}/Views/{1}/{0}.htm",
"~/Areas/{2}/Views/Shared/{0}.html",
"~/Areas/{2}/Views/Shared/{0}.htm"
};
AreaMasterLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.html",
"~/Areas/{2}/Views/{1}/{0}.htm",
"~/Areas/{2}/Views/Shared/{0}.html",
"~/Areas/{2}/Views/Shared/{0}.htm"
};
AreaPartialViewLocationFormats = new[]
{
"~/Areas/{2}/Views/{1}/{0}.html",
"~/Areas/{2}/Views/{1}/{0}.htm",
"~/Areas/{2}/Views/Shared/{0}.html",
"~/Areas/{2}/Views/Shared/{0}.htm"
};
ViewLocationFormats = new[]
{
"~/Views/{1}/{0}.html",
"~/Views/{1}/{0}.htm",
"~/Views/Shared/{0}.html",
"~/Views/Shared/{0}.htm"
};
MasterLocationFormats = new[]
{
"~/Views/{1}/{0}.html",
"~/Views/{1}/{0}.htm",
"~/Views/Shared/{0}.html",
"~/Views/Shared/{0}.htm"
};
PartialViewLocationFormats = new[]
{
"~/Views/{1}/{0}.html",
"~/Views/{1}/{0}.htm",
"~/Views/Shared/{0}.html",
"~/Views/Shared/{0}.htm"
};
FileExtensions = new[]
{
"html",
"htm",
};
}
protected virtual string GetContent(string viewFilePath)
{
string result = null;
if (!string.IsNullOrWhiteSpace(viewFilePath))
{
if (_useCache)
{
result = TryCache(viewFilePath);
}
if (result == null)
{
using (StreamReader streamReader = File.OpenText(viewFilePath))
{
result = streamReader.ReadToEnd();
}
result = ParseContent(result);
if (_useCache)
{
CacheIt(viewFilePath, result);
}
}
}
return result;
}
static readonly Regex TildaRegularExpression = new Regex(#"~/", RegexOptions.Compiled);
/// <summary>
/// Finds all tilda paths in the content and replace it for current path
/// </summary>
/// <param name="content"></param>
/// <returns></returns>
protected virtual string ParseContent(string content)
{
if (String.IsNullOrWhiteSpace(content))
{
return content;
}
string absolutePath = VirtualPathUtility.ToAbsolute("~/");
string result = TildaRegularExpression.Replace(content, absolutePath);
return result;
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
HttpContextBase httpContextBase = controllerContext.RequestContext.HttpContext;
string filePath = httpContextBase.Server.MapPath(partialPath);
string content = GetContent(filePath);
return new StaticView(content);
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
HttpContextBase httpContextBase = controllerContext.RequestContext.HttpContext;
string result = null;
if (!string.IsNullOrWhiteSpace(masterPath))
{
string filePath = httpContextBase.Server.MapPath(masterPath);
result = GetContent(filePath);
}
string physicalViewPath = httpContextBase.Server.MapPath(viewPath);
result += GetContent(physicalViewPath);
return new StaticView(result);
}
protected virtual string TryCache(string filePath)
{
HttpContext httpContext = HttpContext.Current;
if (httpContext != null && httpContext.Cache != null)
{
string cacheKey = CacheKey(filePath);
return (string)httpContext.Cache[cacheKey];
}
return null;
}
protected virtual bool CacheIt(string filePath, string content)
{
HttpContext httpContext = HttpContext.Current;
if (httpContext != null && httpContext.Cache != null)
{
string cacheKey = CacheKey(filePath);
httpContext.Cache.Add(cacheKey, content, new CacheDependency(filePath), AbsoluteTimeout.GetValueOrDefault(Cache.NoAbsoluteExpiration), SlidingTimeout.GetValueOrDefault(Cache.NoSlidingExpiration), Priority.GetValueOrDefault(CacheItemPriority.AboveNormal), CacheItemRemovedCallback);
return true;
}
return false;
}
protected virtual string CacheKey(string serverPath)
{
return serverPath;
}
protected virtual void CacheItemRemovedCallback(string key, object value, CacheItemRemovedReason reason)
{
_log.InfoFormat("CacheItemRemovedCallback(string key='{0}', object value = ..., {1} reason={2})", key, reason.GetType().Name, reason);
}
}
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
ViewEngines.Engines.Add(new HtmlStaticViewEngine(new TimeSpan(12,0,0,0)));
}
}
public class StaticView : IView
{
private readonly string _text;
public StaticView(string text)
{
_text = text;
}
public void Render(ViewContext viewContext, TextWriter writer)
{
if (! string.IsNullOrEmpty(_text))
{
writer.Write(_text);
}
}
}
NOTE:
This code is tested only with simple usage for rendering
partial views
Is there a reason you are holding the content in an HTML file rather than a partial view?
If you create a file called snippet.ascx in your Views/Shared folder you can import the content of that snippet.ascx file into any view by using <% Html.RenderPartial("snippet"); %>
To include static html file into a MVC View goes like this:
<!-- #include virtual="~\Content\snippet.htm" -->
For ASP .NET Core 3.1 Razor page you can do it like this:
#Html.Raw(System.IO.File.ReadAllText("wwwroot/Content/snippet.html"));
See documentation regarding static files here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-3.1