Creating a component by overriding BlazorComponent.BuildRenderTree(RenderTreeBuilder builder) - c#

I am learning Blazor.
https://learn-blazor.com/
I am having some difficulty creating a component in C# by overriding the BuildRenderTree(RenderTreeBuilder builder) method of the BlazorComponent class.
Here is my class:
public class TestComponent : BlazorComponent
{
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(1, "p");
builder.OpenElement(2, "strong");
builder.AddContent(3, "hello");
builder.CloseElement();
builder.CloseElement();
base.BuildRenderTree(builder); // With or without this line it doesn't work
}
}
I use it in my page like this:
<TestComponent></TestComponent>
I have tested it with and without that last line base.BuildRenderTree(builder); but either way it doesn't render. I've made the component childishly simple (just a paragraph tag, strong tag and one word of content) so I'm lost as to why it won't render. The code builds just fine.
Can anybody see what I did wrong please?

First off don't use that web site anymore. I've learned Blazor through that web site. It is an excellent web site, and the guy did a superb work. But alas, he stopped updating it, at least for the last six months. The materials have become old and useless. Right now, I'm not aware of any good substitution.
Try this:
Place base.BuildRenderTree(builder); at the start of the BuildRenderTree method , not at the end.
Use ComponentBase instead of BlazorComponent...
BlazorComponent is dead...
Always start with the value 0 for the sequence parameter.

Related

How call Screenshot method after each Selenium action

I work with Specflow (if there is such a function there)
Programming language C#.
I want a screenshot to be taken after each selenium action.
Why? -> I want that after the first automation, a series of pictures of the successful test run is created (so that business analysts in the future can quickly see via pictures, what is tested with which test caseid).
It should be possible to specify via a flag whether the screenshot should be created or not. So my main problem is:
How do I ensure that my screenshot function is automatically called after each "driver.FindElement.... "and then "variable.click" or similar?
I don't want to manually insert "makeScreenshot()" everywhere.
It would be wonderful if a different method could be called after each method call. That looks up what the "command is". If the syntax then matches something like "Click()", the screenshot is triggered, otherwise not.
If there is no such thing. Something like "Screenshot(variable.Click())" would also be conceivable. That would still be clean and easily implemented everywhere via copy paste.
Does anyone have an idea or a link? (I'm a bit of a noob and need code examples to get started)
Potential solution 1:
You could add a extension method to your project for IWebElement, which would allow you to create your own custom click and find methods that screenshot after clicking. For example:
public static class IWebElementExtensions
{
public static void ClickAndScreenshot(this IWebElement element,
IWebDriver driver,
ScenarioContext scenarioContext)
{
element.Click();
Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
ss.SaveAsFile($"{scenarioContext.ScenarioInfo.Title}_{scenarioContext.StepContext.StepInfo.Text.Replace("\"", "")}.png",
ScreenshotImageFormat.Png);
}
}
If you add the above class to your project and reference it in your steps, it would click the element, and then take a screenshot and add the scenario and step info to the filename to identify it later (consider how you plan to manage these screenshots, might be worth adding a subfolder per scenario, or datetimes to the filename for diagnostics).
You can then make use of this method in your Specflow steps:
[When(#"I click a login button")]
public void WhenIClickALoginButton()
{
By someLoginButton = By.Id("login");
_driver.FindElement(someLoginButton).ClickAndScreenshot(_driver, _scenarioContext);
}
You could do something similar for finding the element. You could create an extension method that finds the element, takes a screenshot and then returns the element as a return type to be used by your WebDriver.
You would have to change your current click() methods to take advantage of this new method (find and replace should help make this trivial), but your screenshot code would all be in one place if you need to change it. Doing it this way means you can pick and choose when to call that method as well depending on your steps, as you could stick to the original Click() method if not interested in a screenshot in a particular step.
Potential Solution 2:
I feel like taking a screenshot after every Specflow step rather then each Selenium action is worth mentioning as a potential solution, focusing on chunks of user actions rather then every Selenium action.
For example, you could configure a hooks file to take a screenshot after every specflow step:
[Binding]
public class Hooks
{
IWebDriver _driver;
public Hooks(IWebDriver driver)
{
_driver = driver;
}
[Scope(Tag = "screenshot")]
[AfterStep]
public void TakeScreenshotAfterStep(ScenarioContext scenarioContext)
{
Screenshot screenshot = ((ITakesScreenshot)_driver).GetScreenshot();
screenshot.SaveAsFile($"{scenarioContext.ScenarioInfo.Title}_{scenarioContext.StepContext.StepInfo.Text}.png",
ScreenshotImageFormat.Png);
}
[AfterScenario]
public void AfterScenario()
{
_driver.Dispose();
}
}
For a example Feature:
Feature: Login
#screenshot
Scenario: Successful Login
GIVEN I navigate to stack overflow
WHEN I login
THEN I am logged in
#someOtherTag
Scenario: API test with no UI
GIVEN I have a cool API
WHEN I do a GET
THEN I GET some cool stuff
This would generate 3 screenshots after each step for the Successful login scenario, but it wouldn't take any for the API test due to the tag scope on the after step, which should tick the box around being able to specify when to do this.
The above relies on your Specflow steps not being too large though... if you're doing multiple large chunks of user actions within one step, it may skip a lot, but if that's only a rare occurrence you could do some extra screenshot taking within those steps using the extension from potential solution 1.
I hope this helps, I apprieciate it's not a pure answer but from experience of when these sorts of screenshots can be useful, I'd recommend solution 2 and use it as an opportunity to make sure your Specflow steps aren't doing too much.

Language component in URL of default Identity UI for asp.net 6

I have an application which I must port to asp.net 6. I try to implement the authentication logic with scaffolded default identity UI pages.
The application uses URLs which start with a path component which holds the user’s language, then followed by the concrete path components. Something like:
/{language}/product/{product}
Now I try to establish this url schema also with the asp.net identity default UI pages. For example, the login page url should be look something like this:
/en/login
/fr/login
/it/login
However, up to now I had only little success in doing so. In changing the #page directive in the scaffolded pages I was able to introduce the {language} path component. However, how do I now tell the cookie middleware to integrate the current {language} placeholder into the redirect? Something like this:
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/{language}/Login";
});
Is this feasible in some way or another or is there even a more solid way to accomplish the goal?
Update
Up to now I came up with a solution and posted it as an answer, since it works. However if anybody knows a more sophisticated approach, please post it, I feel that the way I did this is really ugly and I cannot believe that there is no cleaner way to accomplish this, since also Microsoft uses the Url schema I try to implement in their websites.
One possibility I've found is to use the CookieAuthenticationOptions.Events-instance. This seems a feasible way, however it seems to me extremely brutish and one has to register to every event which is concerned and every scaffolded page has to be changed (redirects etcetera).
However, as long as no other solution is provided, this may help someone:
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/language/Login";
options.Events.OnRedirectLogin=>(context){
// here would stand some Ajax-checks ...
var myLanguage= ... // detection of the language from the query string
context.Response.Redirect(context.RedirectUri.Replace("/language/", myLanguage));
}
});
The above code is best refactored in a new class which derives from CookieAutenticationEvents, where then proper handling can be done for each event. So the only assigment in the Program.cs file is the assignment of the custom authentication events class. The original class seems a bit quirky and depending on the purpose of the derived class, it is either better to initially assign custom events while constructing the instance or to override the methods which raise the assigned event handlers.
Within the pages, the language can be declared via the page directive:
#page "/{language}/login"
#page "/{language}/loginWith2fa"
etcetera
The code behind then will be changed, for example the signature of the get and set method will be extended with the language-parameter.
public async Task<IActionResult> OnGetAsync(string language,bool rememberMe, string returnUrl = null) {
and additionally, any url references in the code behinds must be changed. Since this way is so ugly, I tried to completely abstain from the default identity ui. In this post I ask for a way to do so.

Is there a way to alter ChildContent in Blazor

I'd like to alter ChildContent my component receives from the parent like this:
<Markdown>
# Title
Some _Content_
</Markdown>
To interpret this content I would need to do something like Markdown.ToHTML(#ChildContent).
But as ChildContent is not a string, I need some means to access the ChildContent and retrieve it as string. Is this possible and how can it be done? Any other idea to solve this?
This isn't impossible but it's not a great way to go.
In order to take a render fragment and produce HTML, it needs to be run through a renderer. This isn't a particularly simple thing to achieve. If you want to see an example you can look at the Test Renderer produced by Steve Sanderson for his unit testing prototype.
You could have a go at creating your own renderer but I would suggesting considering a different approach.
Most probably you have already found a solution, but take a look at the code snippet bellow (.NET 5.0):
var builder = new RenderTreeBuilder();
builder.AddContent(0, this.ChildContent);
var frame = builder.GetFrames().Array.FirstOrDefault(x => new[]
{
RenderTreeFrameType.Text,
RenderTreeFrameType.Markup
}.Any(t => x.FrameType == t));
var value = frame?.MarkupContent;
Adding content to builder adds two frames, a region one and a text/markup one, depending on whether ChildContent contains plain text of HTML. Instead of guessing however, it is safer to use FirstOrDefault.
NB: This is kind of a hack and is not guaranteed that would work in future version of Blazor. I haven't used it with Blazor 6.0 or 7.0 (in preview, yet to be released) but I am able to retrieve the content of, pardon me, ChildContent.

Ways to share common functions betweed few pages in ASP.NET

This is possibly very lame question and I lack knowledge about ASP.Net. In this case a link to an article explaining would be very welcome.
I'm working on web-site on ASP.NET with C# as codebehind. My current project involves developing few pages with very similar functionality and a many functions are the same. For example
private void PermissionCheck()
{
if (null == Session["UserID"] ||
null == Session["ProjectID"] ||
null == Session["AssetID"] ||
null == Session["ProjectName"])
{
Response.Redirect("~/Login.aspx");
}
}
Would be the same on 2 pages. Some other things are the same as well. I would like to put this into common base class. But there are other functions that don't really belong to pages at all:
private string GetAttachmentTempPath()
{
return Request.PhysicalApplicationPath + WebConfigurationManager.AppSettings.Get("AttachmentsTempFolder");
}
I would like to move this into Attachment class, but to get the physical path of the application, I need to pass in Request object into that method, which is not really nice, as it couples Attachment class with Page.Request object.
Is there any way to move these functions somewhere else without needing to pass Page.Request objects around??
p.s. The appliction is huge, and there is no scope to change the entire architecture.
For your permission thing you could make a base page class:
class BasePage : Page
{
...
protected override OnInit() {
// do check here
}
}
Now you can implement your page like this class MyOtherPage : BasePage { ... }
The OnInit gets executed everytime your MyOtherPage gets loaded.
You can see a complete page lifecycle here: Link
For your other problem: Consider to implement a global available static tool class
Update
A good approach for making things like web.config easier to access is a Singleton. In asp.net a singleton is only created once and lives until the asp worker process gets stopped . So this values are shared across the whole asp.net application. This is also good for storing data in a global context that you dont want to get out of your database or file anytime a user makes a page request (for example a version number or things like that)
Update 2
To access the request without passing it to every function, use this:
HttpContext.Current.Request
Base page is a good option for reusable code in Page level. Other than that for things like configuration values it's good to come up with utility classes specifically for those methods base don there type of operations.
If you need to avoid passing in Page object into these types of utility methods,
HttpContext
class would be handy because you can access many of the ASP.Net object through static members through this class. HttpConext # MSDN
If you have similar functions behind the page, you can use ASP.NET WEb User Control.
You can create the functions in the usercontrol and use the control in the pages where necessary.
Have look at this article about Web User Control in Asp.Net

Problem grasping webpart communication

I'm having trouble understanding some web part communication code, and how to make it work as needed. I'm fairly new to web parts, so I figure I'm over complicating it.
I have
public interface IFormTypeRID
{
int FormTypeRID { get; }
}
For this page, I have a ListControl on the left which is a web part. When you select something with this list control, it posts back and sends this interface to the MainForm web part So I have this on the receiving end:
private IFormTypeRID theProvider;
[ConnectionConsumer("FormTypeRID Consumer", "FormTypeRIDConsumer")]
public void InitializeProvider(IFormTypeRID provider)
{
theProvider = provider;
FormTypeRID = theProvider.FormTypeRID;
}
Now, my problem is that InitializeProvider happens after Page_Load.
This means that when a post back happens from inside the MainForm webpart, the FormTypeRID is never sent in. Well, thats easy just store it in view state or a hidden field.
But theres the problem.
How do I act on FormTypeRID being set if it's after PageLoad. Currently, I just have a setter method that calls the appropriate functions. This is troublesome however because the code in the setter must be executed twice. This is because FormTypeRID must be set in Page_Load because it is unknown whether our provider will be giving us our FormTypeRID or not(because we do not know if the post back happened because of the other webpart, or because of the FormMain)
I know I explained that horribly. But basically, how do you tell if a postback happened(and therefore a page_load) from one webpart(the provider) or another?(the consumer)
The answer to all of this is non-trivial.
I ended up writing my own "webpart communication" which actually ended up being a lot cleaner than ASP.Net's and it will work during Init and Load and so on.

Categories