Blazor Application - pass a Query String to the app on startup - blazor-server-side

I have a Blazor application how can I pass a Query String to the app on startup?
I want to pre-populate a form field and query a database with the query string value on startup.
Something like this `http://www.somesite.com?Company=Google
I have seen the following - using query string in pages. But how to you accept the query string on start up?
https://www.mikesdotnetting.com/article/340/working-with-query-strings-in-blazor
Where in the app page or code - Startup.cs / Program.cs - do you check for the query string.
thx in advance

This Microsoft article will explain it better than I can:
https://learn.microsoft.com/en-us/aspnet/core/blazor/routing?view=aspnetcore-3.1
Here is a summary of relevant parts.
On your page you can have this:
#page "/Users/{text}"
Then in your code create a parameter:
[Parameter]
public string Company { get; set; }
Then if you navigate to: yoursite.com/Users/Google
your parameter will be populated, and you can do any loading / or other prerendering in OnInitializedAsync method.
// this is from one of my projects
protected override async Task OnInitializedAsync()
{
// load the Categories
this.Categories = await HelpCategoryService.GetHelpCategoryList();
}
You can have multiple routes on the same page, so you could have:
#page "/Users/
#page "/Users/{Company:string}"
Maybe that points you in the right direction.

Related

In ASP.NET Core, is it possible to generate a URI in the controller for a Get action that takes two parameters? If so how?

I have an association controller called ConnectionManagerCategoriesController. It has two Get methods on it. One to get all Categories for a ConnectionManager and one to only retrieve one Categoy for the ConnectionManager based upon the name. I have a Post to create a new category and I am trying to generate a uri for LinkGenerator. However when the URI that is created, it uses the GetConnectionManagerCategories method instead of the GetConnectionManagerCategory. I dont know why or how to do it differently.:
[Route("api/connectionmanagers/{connectionManagerID:int}/categories")]
[ApiController]
public class ConnectionManagerCategoriesController : ControllerBase
{
private readonly LinkGenerator _linkGenerator;
[HttpGet]
public async Task<ActionResult<IEnumerable<ConnectionManagerModel>>> GetConnectionManagerCategoriesAsync(int connectionManagerID){}
[HttpGet("{categoryName}", Name = "GetConnectionManagerCategoryAsync")]
public async Task<ActionResult<ConnectionCategoryModel>> GetConnectionManagerCategoryAsync(int connectionManagerID, string categoryName){}
[HttpPost]
public async Task<ActionResult<ConnectionCategoryModel>> AddConnectionCategoryAsync(int connectionManagerID, string categoryName, [FromHeader(Name = "x-requestid")] string requestId)
{
var url = _linkGenerator.GetUriByRouteValues(HttpContext,
"GetConnectionManagerCategoryAsync",
values: new { connectionManagerID, categoryName = commandResult.CategoryName });
return Created(url, commandResult);
}
It returns the following uri to Swagger: 'http://localhost:6704/api/connectionmanagers/1/categories?categoryName=Almost'
However, when I log the uri in the code it is: http://localhost:6704/api/connectionmanagers/1/categories/newvalueadded
Is this even possible?
You have to show how are trying to run the action, in order to get some explanations. Routing is very tricky and it is better not to try to create routes the way you are creating.
IMHO , it is always a good idea to define the whole route, not just the part. Especially if you use Swager
[HttpGet("{~/api/connectionmanagers/{connectionManagerID:int}/categories/{categoryName}")]
public async Task<ActionResult<ConnectionCategoryModel>> GetConnectionManagerCategoryAsync(int connectionManagerID, string categoryName){}

Globally available values in Blazor Server (and changing them during runtime)

In Blazor server the "appsettings.json" file is great for storing globally accessible variables. But what if these need changing during runtime? For example, lets say we have a stored value for "IsMaintenanceMode".
Given that;
"IsMaintenanceMode" may need to be set to "True" during runtime (to then direct users to a maintenance page)
If we were using a middleware to check this value for True (i.e. redirect the user to maintenance page) - then we would not want to look this variable up each time - eg from a database - on every request.
Traditionally this might have been accomplished using Application variables but I'm just not sure of the best approach with Blazor.
So my question is - what's the best way of storing this value in a way that can be "cached" for ease of lookup, but also easily changed during runtime?
Thanks for any advice.
StateServer.cs
public class StateServer {
public bool IsMaintenanceMode {get; set;}
}
Add it in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<StateServer >();
}
Component.razor // Can be layout, main page, etc.
#inject StateServer _stateServer
#if (_stateServer.IsMaintenanceMode){
<Warning />
}
else {
<Body />
}
#code {
}
Or, you can check the value in one of the page lifecyle events, and navigate to whatever page you like.

sitefinity ActionResult missing query string

I have widget and in the ActionResult method it get the query string as parameters. The widget takes the query string and calls a API. Is there anyway I can display a message to the view if its missing the query string?
Code
public ActionResult Index(string UserId, string BlogId)
Yep, do whatever you want
if(String.IsNullOrEmpty(UserId)){
// you get the idea
}
I would do one of the following
Add a property to the model, then handle that state in the view
Load a custom view that's just the message (cleanest)
Check for the empty querystring and do a return this.RedirectPermanent(url); to add the querystring to the page so there's no way it loads without something.

asp.net mvc add parameter with each action view

I have a site which have many action like article, blog, news, stories, myths, books, audio, video.
Now I want if i pass a query string in index action like
wwww.mysite.com/english
then every action must be have this parameter automatically like
wwww.mysite.com/article/englishwwww.mysite.com/blog/englishwwww.mysite.com/news/englishwwww.mysite.com/stories/englishwwww.mysite.com/myths/englishwwww.mysite.com/books/englishwwww.mysite.com/audio/englishwwww.mysite.com/video/english
Please help me and suggest a good way
Store the passed passed parameter in a session variable and then access on each action. Example:
public ActionResult Index(string lang)
{
Session["Language"]= lang;
return View();
}
And then fetch in other actions like:
public ActionResult News()
{
string lang= Session["Language"].ToString();
// Do something with the lang...
return View();
}

The view or its master was not found or no view engine supports the searched locations

Error like:The view 'LoginRegister' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/MyAccount/LoginRegister.aspx
~/Views/MyAccount/LoginRegister.ascx
~/Views/Shared/LoginRegister.aspx
~/Views/Shared/LoginRegister.ascx
~/Views/MyAccount/LoginRegister.cshtml
~/Views/MyAccount/LoginRegister.vbhtml
~/Views/Shared/LoginRegister.cshtml
~/Views/Shared/LoginRegister.vbhtml
Actually my page view page is ~/Views/home/LoginRegister.cshtml so what i do
and my RouteConfig is
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "MyAccount", action = "LoginRegister", id = UrlParameter.Optional }
);
}
}
Be careful if your model type is String because the second parameter of View(string, string) is masterName, not model. You may need to call the overload with object(model) as the second parameter:
Not correct :
protected ActionResult ShowMessageResult(string msg)
{
return View("Message",msg);
}
Correct :
protected ActionResult ShowMessageResult(string msg)
{
return View("Message",(object)msg);
}
OR (provided by bradlis7):
protected ActionResult ShowMessageResult(string msg)
{
return View("Message",model:msg);
}
Problem:
Your View cannot be found in default locations.
Explanation:
Views should be in the same folder named as the Controller or in the Shared folder.
Solution:
Either move your View to the MyAccount folder or create a HomeController.
Alternatives:
If you don't want to move your View or create a new Controller you can check at this link.
In Microsoft ASP.net MVC, the routing engine, which is used to parse incoming and outgoing URL Combinations, is designed with the idea of Convention over Configuration. What this means is that if you follow the Convention (rules) that the routing engine uses, you don't have to change the Configuration.
The routing engine for ASP.net MVC does not serve web pages (.cshtml). It provides a way for a URL to be handled by a Class in your code, which can render text/html to the output stream, or parse and serve the .cshtml files in a consistent manner using Convention.
The Convention which is used for routing is to match a Controller to a Class with a name similar to ControllerNameController i.e. controller="MyAccount" means find class named MyAccountController. Next comes the action, which is mapped to a function within the Controller Class, which usually returns an ActionResult. i.e. action="LoginRegister" will look for a function public ActionResult LoginRegister(){} in the controller's class. This function may return a View() which would be by Convention named LoginRegister.cshtml and would be stored in the /Views/MyAccount/ folder.
To summarize, you would have the following code:
/Controllers/MyAccountController.cs:
public class MyAccountController : Controller
{
public ActionResult LoginRegister()
{
return View();
}
}
/Views/MyAccount/LoginRegister.cshtml: Your view file.
In your LoginRegister action when returning the view, do below, i know this can be done in mvc 5, im not sure if in mvc 4 also.
public ActionResult Index()
{
return View("~/Views/home/LoginRegister.cshtml");
}
Check the build action of your view (.cshtml file) It should be set to content. In some cases, I have seen that the build action was set to None (by mistake) and this particular view was not deploy on the target machine even though you see that view present in visual studio project file under valid folder
This could be a permissions issue.
I had the same issue recently. As a test, I created a simple hello.html page. When I tried loading it, I got an error message regarding permissions. Once I fixed the permissions issue in the root web folder, both the html page and the MVC rendering issues were resolved.
Check whether the View (.ASPX File) that you have created is having the same name as mentioned in the Controller. For e.g:
public ActionResult GetView()
{
return View("MyView");
}
In this case, the aspx file should be having the name MyView.aspx instead of GetView.aspx
I got this error because I renamed my View (and POST action).
Finally I found that I forgot to rename BOTH GET and POST actions to new name.
Solution : Rename both GET and POST actions to match the View name.
If the problem happens intermittently in production, it could be due to an action method getting interrupted. For example, during a POST operation involving a large file upload, the user closes the browser window before the upload completes. In this case, the action method may throw a null reference exception resulting from a null model or view object. A solution would be to wrap the method body in a try/catch and return null. Like this:
[HttpPost]
public ActionResult Post(...)
{
try
{
...
}
catch (NullReferenceException ex) // could happen if POST is interrupted
{
// perhaps log a warning here
return null;
}
return View(model);
}
I had this same issue.
I had copied a view "Movie" and renamed it "Customer" accordingly.
I also did the same with the models and the controllers.
The resolution was this...I rename the Customer View to Customer1 and
just created a new view and called it Customer....I then just copied
the Customer1 code into Customer.
This worked.
I would love to know the real cause of the problem.
UPDATE
Just for grins....I went back and replicated all the renaming scenario again...and did not get any errors.
I came across this error due to the improper closing of the statement,
#using (Html.BeginForm("DeleteSelected", "Employee", FormMethod.Post))
{
} //This curly bracket needed to be closed at the end.
In Index.cshtml view file.I didn't close the statement at the end of the program. instead, I ended up closing improperly and ran into this error.
I was sure there isn't a need of checking Controller ActionMethod code because I have returned the Controller method properly to the View. So It has to be the view that's not responding and met with similar Error.
If you've checked all the things from the above answers (which are common mistakes) and you're sure that your view is at the location in the exceptions, then you may need to restart Visual Studio.
:(
In my case, I needed to use RedirectToAction to solve the problem.
[HttpGet]
[ControleDeAcessoAuthorize("Report/ExportToPDF")]
public ActionResult ExportToPDF(int id, string month, string output)
{
try
{
// Validate
if (output != "PDF")
{
throw new Exception("Invalid output.");
}
else
{
...// code to generate report in PDF format
}
}
catch (Exception ex)
{
return RedirectToAction("Error");
}
}
[ControleDeAcessoAuthorize("Report/Error")]
public ActionResult Error()
{
return View();
}
I ran into this a while ago and it drove me crazy because it turned out to be simple. So within my View I was using a grid control that obtained data for the grid via an http request. Once the middle tier completed my request and returned the dataset, I received the same error. Turns out my return statement was 'return View(dataset);' instead of 'return Json(dataset);
I couldn't find any solution to this problem, until I found out the files didn't exist!
This took me a long time to figure out, because the Solution Explorer shows the files!
But when I click on Index.cshtml I get this error:
So that was the reason for this error to show. I hope this answer helps somebody.