Unable to Get Syntax Correct for Writing to Text File in .NET Core 2.2 Razor Pages - file-io

It used to be simple to find the path to a folder with text files and either create and write or add to an existing file.
Now, I just can't get the syntax right.
var userData = firstName + "," + lastName +
"," + email + Environment.NewLine;
var dataFile = Server.MapPath("~/App_Data/data.txt");
File.AppendAllText(#dataFile, userData);
result = "Information saved.";
_context.Courses_New.Add(Courses_New);
await _context.SaveChangesAsync();
The "File." is underlined in red and so is the "Server.".
I have seen examples that mentioned adding this code to get the "environment", but I get all red saying that HomeController must have a return value. The Create page is the return value.
private IHostingEnvironment _env;
public HomeController(IHostingEnvironment env)
{
_env = env;
}
The code below is at the top of my Razor Page and it uses up the return value. So no matter what I name HomeController to, it gives me an error:
private readonly OESAC.Models.MyDbContext _context;
public CreateModel(OESAC.Models.MyDbContext context)
{
_context = context;
}
Supposedly I can reference the _env variable to combine a path.
Goal is to simply write success and failure to a text file during a Create row Task.

If I understand the question correctly you are using Razor Pages. Controllers are used for WebApi and MVC but not needed for Razor Pages. But the same principles can be applied. As long as the other classes you need are configured with Dependency Injection (DI) you can just add them onto your page model constructor. So modify CreateModel as follows:
private readonly OESAC.Models.MyDbContext _context;
private IHostingEnvironment _environment { get; private set; }
public CreateModel(OESAC.Models.MyDbContext context, IHostingEnvironment hostingEnvironment)
{
_context = context;
_environment = hostingEnvironment;
}
Then later in a Page event you could do something like the following:
public async Task<IActionResult> OnPostAsync() {
var webRootPath = _environment.WebRootPath;
var dataPath = Path.Combine(webRootPath, "data.txt");
...
}
Note this will write a file in your web root which might be publically accessible and not what you want. Using a Logger might be a better approach if you are looking to record info about the inner runnings of your task (see here for more info)

Related

Using GetGridHtml in a controller in Umbraco 10

I have made a simple Api controller on my umbraco website, that simply searches some nodes for some properties and returns the content from those properties in json.
One of the properties is an umbraco grid. Technically that is also json, and I could successfully get the content with some elaborate JObject querying. But from the view side there is access to a "GetGridHtml" helper function that does that for you.
So my question is, how do I achieve that in a controller? I got the node as IPublishedContent which incidentally has that helper function, but it wants an IHtmlHelper which isn't available in this context. So what do I do?
[HttpGet]
[Route("api/myapp/version/")]
public IActionResult GetLatestMyAppVersion()
{
var releaseNote = _umbracoHelper.ContentAtXPath("//releaseNoteList").First().Children().OrderByDescending(x => x.Value<DateTime>("releaseDate")).First();
var ver = releaseNote.Value<string>("myAppReleaseVersion");
var date = releaseNote.Value<DateTime>("releaseDate");
var desc = releaseNote.GetGridHtml(?????, "mainContent", "Clean"); // this is where IHtmlHelper is needed
return Ok(new { Application = "MyApp", Version = ver, ReleaseDate = date.ToString("yyyy-MM-dd"), Description = desc });
}
If you want to get the Ihtmlhelper inside the controller method, I suggest you could inject it by inside the controller construct method and then you could use it inside your codes.
More details, you could refer to below codes:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
private readonly IHtmlGenerator _htmlGenerator;
private readonly IHtmlHelper _helper;
public HomeController(IHtmlHelper helper, IHtmlGenerator htmlGenerator, ILogger<HomeController> logger)
{
_logger = logger;
_helper = helper;
_htmlGenerator = htmlGenerator;
}

In-Memory Cache with .NET EF Core throws error

I have a .Net Core application with EF which returns a page called Customer as home page. But I need show an app not available page (AppNotAvialable.cshmtl) when the user tries to access the application on a holiday(holiday list is stored in a table)instead of the Customer page. Instead of querying the holiday list table every time the home page is accessed I am trying to use the In-Memory Cache so I can store the query response in cache and use them in the controller. I am implementing the cache for the 1st time and below is what I tried
public class CustomersController : Controller
{
private readonly SurplusMouseContext _context;
private readonly IMemoryCache memoryCache;
.......................
public async Task<IActionResult> Index(string sortOrder, string searchString,
int? pageNumber, string currentFilter)
{
int holidaycheck;
var timeUtc = DateTime.UtcNow;
var easternZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var todayDt = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, easternZone);
bool isExist = memoryCache.TryGetValue("HolidayWk", out holidaycheck);
if (!isExist)
{
holidaycheck = (from hc in _context.HolidayWeeks
where hc.HolidateDate.Date == todayDt.Date
select hc).Count();
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromHours(2));
memoryCache.Set("HolidayWk", holidaycheck, cacheEntryOptions);
}
if (holidaycheck != 0)
{
return View("/Views/Customers/AppNotAvailable.cshtml");
}
else
{
when I try to debug the application it throws error like below
Can anyone please suggest if I am implementing the in Memory Cache here correct/missing anything and where should I be doing the cacheMemory.Remove() Any help is greatly appreciated
The first step to check:
In your question, it is possible you didn't initialize MemoryCache object in the constructor.
There is an example of MemoryCache.
1 - You should register MemoryCache in services like this:
services.AddMemoryCache();
2 - Inject IMemoryCache interface in your controller and initialize it.
public class YourController : Controller
{
private readonly IMemoryCache _memoryCache;
public YourController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache
}
}
3 - Using memory cache:
public async Task<IActionResult> Index(string sortOrder, string searchString,
int? pageNumber, string currentFilter)
{
bool isExist = _memoryCache.TryGetValue("HolidayWk", out holidaycheck);
}

ASP.NET Core 3.0 HttpContext.Current.Server.MapPath

Im migration a classic C# MVC project to .NET Core and I have a Utility Project where I need to get access of App_Data folder.
I already create in this new project my App_Data folder outside wwwroot but I need to get reference to it from this Utility Project.
This is my old code:
public static class Common
{
private static void DeleteTestFiles()
{
var path = HttpContext.Current.Server.MapPath("~/App_Data/Files");
.....
}
}
I was reading that in 3.0 there is a way to do this, here the example:
private readonly IWebHostEnvironment _hostingEnvironment;
public HomeController(IWebHostEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
public ActionResult Index()
{
string webRootPath = _hostingEnvironment.WebRootPath;
string contentRootPath = _hostingEnvironment.ContentRootPath;
return Content(webRootPath + "\n" + contentRootPath);
}
But above code is for a Controller that lives in the web project. My Utility Projects common class is not a Controller and is a static class so I cannot have constructor in order to have IWebHostEnvironment to be injected automaticly.
Any clue how can I do get the path or maybe I need to manually inject IWebHostEnvironment but don't have a clue.
Don't use a static class. You can keep something similar to your class, and register it as a singleton.
public class Common
{
private readonly IWebHostEnvironment _env;
public Common(IWebHostEnvironment env)
{
_env = env;
}
private void DeleteTestFiles()
{
var path = Path.Combine(_env.ContentRootPath, "App_Data/Files");
.....
}
}
Then, in Startup.ConfigureServices:
services.AddSingleton<Common>();
Finally, inject Common where you need it, instead of just statically referencing the class. This is how things work in DI, statics are a no-go.
UPDATE:
In order this to work, because the Utility project is referencing Microsoft.NETCore.App and not Microsoft.AspNetCore.App framework then you have to use IHostEnvironment instead of IWebHostEnvironment.
IWebHostEnvironment actually implements IHostEnvironment interface.
Did the test and all working good! I could get the ContentRootPath.
public class Common
{
private readonly IHostEnvironment _env;
public Common(IHostEnvironment env)
{
_env = env;
}
private void DeleteTestFiles()
{
var path = Path.Combine(_env.ContentRootPath, "App_Data/Files");
.....
}
}
.Net 6 (.NetCore 3 and above)
For example I want to locate ~/wwwroot/CSS
public class YourController : Controller
{
private readonly IWebHostEnvironment _webHostEnvironment;
public YourController (IWebHostEnvironment webHostEnvironment)
{
_webHostEnvironment= webHostEnvironment;
}
public IActionResult Index()
{
string webRootPath = _webHostEnvironment.WebRootPath;
string contentRootPath = _webHostEnvironment.ContentRootPath;
string path ="";
path = Path.Combine(webRootPath , "CSS");
//or path = Path.Combine(contentRootPath , "wwwroot" ,"CSS" );
return View();
}
}

Query the authenticated user object too often within a http request

I am using asp.net core mvc with asp.net identity.
My ApplicationUser has a property: Country => 'GB' or 'FR' etc...
I want to set the System.Threading.Thread.CurrentThread.CurrentCulture to the value read from the applicationUser.Country. to display all datetime/number values correctly in my views as set by the user.
Thus I created this action filter:
public class LanguageActionFilter : ActionFilterAttribute
{
private readonly ILogger _logger;
private UserManager<ApplicationUser> _userManager;
public LanguageActionFilter(ILoggerFactory loggerFactory, UserManager<ApplicationUser> userManager)
{
_logger = loggerFactory.CreateLogger("LanguageActionFilter");
_userManager = userManager;
}
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var user = await _userManager.GetUserAsync(context.HttpContext.User);
Thread.CurrentThread.CurrentCulture = new CultureInfo(user.Country);
await base.OnActionExecutionAsync(context, next);
}
}
On the action/controller where this actionfilter is set I also run this code:
public async Task<IActionResult> Index()
{
var user = await this.userManager.GetUserAsync(User);
var todos = await service.GetTodosAsync(user.Id);
return View(todos);
}
At the moment I call the this.userManager.GetUserAsync(User);
TWO TIMES !
Then I thought about passing the user object to the
context.HttpContext.Items.Add("applicationUser", user);
and grab this user object again within the Index() action method:
var user = (ApplicationUser)base.HttpContext.Items["applicationUser"];
That worked, but is that a good idea? Do you see any problems with that approach?
What you did is fine...
I'm quoting from the definition of the HttpContext class :
/// <summary>
/// **Gets or sets a key/value collection that can be used to share data within the scope of this request.**
/// </summary>
public abstract IDictionary<object, object> Items { get; set; }
Edit : It seems ef core doesn't support first level cache. So my idea went for nothing
Your code works, but i think you won't gain considerable performance.
You probably use aspnet identity with entity framework. Since ef supports first level cache. , if you call this.userManager.GetUserAsync(User); more than one, ef retrieves user entity from database only once. As a result two ways approximately have same effect for performance. I wouldn't use HttpContext.Items for your case.

ASP.NET 5 (MVC6) How to seed users

How would you seed users? I am following their documents here, but they only show how to seed data that is inserted directly by the ApplicationDbContext.
In the Account controller, the UserManager is created through DI. How would I instantiate a UserManager in the Seed method?
public class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService<ApplicationDbContext>();
var userManager = serviceProvider.GetService<UserManager<ApplicationUser>>();
Then in Startup.cs in the Configure method:
SeedData.Initialize(app.ApplicationServices);
In the startup.cs in the configure method, you can add the following code to get the UserManager and from there seed the users.
var userManager = app.ApplicationServices.GetService<UserManager<ApplicationUser>>();
You would create a class in the lines of
public class UserSeed
{
private ApplicationDbContext _context;
private UserManager<ApplicationUser> _mgr;
public UserSeed(ApplicationDbContext context,UserManager<ApplicationUser> userManager)
{
_context = context;
_mgr = users;
}
public void UserSeedData()
{
var user = new ApplicationUser { UserName = "foo#foo.com", Email = "foo#foo.com" };
var result = _mgr.CreateAsync(user,"fooPassword");
......
......
}
}
In the configure method of your startup.cs take userSeed through DI like
public async void Configure(...., UserSeed userSeedData)
and then inside the method you call
userSeedData.UserSeedData();
Don't use this code as is, you would probably want to check if the user already exists before you create it.
Note: This method will run once every time your application starts.