Contents tagged with Controls
ASP.NET includes a valuable yet not well known extension point called the page parser filter. I once briefly talked about it in the context of SharePoint, but I feel a more detailed explanation is in order.
A page parser filter is a class with a public parameterless constructor that inherits from PageParserFilter and is registered on the Web.config file, in the pages section, pageParserFilterType attribute. It is called when ASP.NET is compiling a page, the first time it is called, for every page. There can be only one page parser filter per web application.
Why is it a parser? Well, it parses – or, better, receives a notification for - every control declared on the markup of a page (those with runat=”server” or contained inside of), as well as all of the page’s directives (<%@ … %>). The control declarations include all of its attributes and properties, the recognized control type and any complex properties that the markup contains. This allows us to do all kinds of crazy stuff:
- Inspect, add and remove page directives;
- Setting the page’s compilation mode;
- Insert or remove controls or text literals dynamically at specific places;
- Add/change/remove a control’s properties or attributes;
- Even (with some reflection magic) change a control’s type or tag.
So, how do we all this? First, the parser part. We can inspect all page directives by overriding the PreprocessDirective method. This is called for all page directives:
The page’s compilation mode is controlled by GetCompilationMode:
As for adding controls dynamically, we make use of the ParseComplete method:
Same for changing a control’s properties:
And even changing the control’s output tag or instance type:
Why would we want to change a control’s type? Well, thing about generics, for once.
And now the filtering part: why is it a filter? Because it allows us to filter and control a number of things:
- The allowed master page, base page class and source file;
- The allowed controls;
- The total number of controls allowed on a page;
- The total number of direct and otherwise references on a page;
- Allow or disallow code and event handler declarations;
- Allow or disallow code blocks (<%= … %>, <%: … %>, <% … %>);
- Allow or disallow server-side script tags (<script runat=”server”>…</script>);
- Allow, disallow and change data binding expressions (<%# … %>);
- Add, change or remove event handler declarations.
All of the filtering methods and properties described below return a Boolean flag and its base implementation may or may not be called, depending on the logic that we want to impose.
Allowing or disallowing a base page class is controlled by the AllowBaseType method (the default is to accept):
For master pages, user controls or source files we have the AllowVirtualReference virtual method (again, the default is true):
Controls are controlled (pun intended) by AllowControl, which also defaults to accept:
This may come in handy to disallow the usage of controls in ASP.NET MVC ASPX views!
The number of controls and dependencies on a page is defined by NumberOfControlsAllowed, NumberOfDirectDependenciesAllowed and TotalNumberOfDependenciesAllowed. Interesting, the default for all these properties is 0, so we have to return –1:
Direct dependencies are user controls directly declared in the page and indirect ones are those declared inside other user controls.
Code itself, including event handler declarations, are controlled by AllowCode (default is true):
If we want to change a data binding expression, we resort to ProcessDataBindingAttribute, which also returns true by default:
For intercepting event handlers, there’s the ProcessEventHook, which likewise returns true by default:
And finally, for code blocks, server-side scripts and data binding expressions, there’s the ProcessCodeConstruct method, which likewise also allows everything by default:
This was in no means an in-depth description of page parser filters, I just meant to give you an idea of its (high) potential. It is very useful to restrict what end users can place on their pages (SharePoint style) as well as for adding dynamic control programmatically in specific locations of the page, before it is actually built.
As usual, let me hear your thoughts!
I have already talked about SignalR in this blog. I think it is one of the most interesting technologies that Microsoft put out recently, not because it is something substantially new – AJAX, long polling and server-sent events have been around for quite some time -, but because of how easy and extensive they made it.
Most of the examples of SignalR usually are about chat. You know that I have been digging into HTML5 lately, and I already posted on media acquisition using HTML5’s getUserMedia API. This time, however, I’m going to talk about video streaming!
I wrote a simple ASP.NET Web Forms control that leverages SignalR to build a real-time communication channel, and this channel transmits images as Data URIs. The source of the feed comes from getUserMedia and is therefore available in all modern browsers, except, alas, one that shall remain unnamed. Any browser, however, can be used to display the streaming feed.
So, the architecture is quite simple:
- One SignalR Hub for the communication channel;
- One ASP.NET Web Forms control, that renders an HTML5 VIDEO tag that is used to display the video being acquired, on any compatible browser.
Here are some nice screenshots of my now famous home wall, where one of the browser instances, Chrome, is broadcasting to Firefox, Opera and Safari.
So, all we need is a control declaration on an ASP.NET Web Forms page, which could look like this:
The non-ordinary properties that the VideoStreaming control supports are:
Interval: the rate in milliseconds that the control broadcasts that the video is being broadcast;
Source: if the control is set as a streaming source, or just as a receiver (default);
And a simple CANVAS element for Target:
The reason for the two main streaming modes, Target and Event are flexibility: with Target, you directly draw the streamed picture on a CANVAS or IMG (it will detect automatically what to use), which needs to be already present, and with Event, you can do your own custom processing.
The source for the VideoStreaming control is this:
Renders a VIDEO tag element with the specified Width and Height;
Register a SignalR hub;
Removes any eventual VIDEO-related attribute that may be present on the control declaration;
Of course, we now need the hub code, which is as simple as it could be, just a method that takes the image as a Data URI and its original dimensions and broadcasts it to the world:
And finally the simple enumerations used by the VideoStreaming control:
And there you have it! Just drop the VideoStreaming control on an ASPX page and you’re done! If you want to have it broadcast, you need to set its Source property to true, for example, on the containing page:
That’s it. Very simple video streaming without the need for any plugin or server. Hope you enjoy it!
I wanted to be able to capture a snapshot and to upload it in AJAX style. Of course, if you know me you can guess I wanted this with ASP.NET Web Forms and client callbacks!
OK, so I came up with this markup:
The properties and events worth notice are:
Width & Height: should be self explanatory;
PictureTaken: a handler for a server-side .NET event that is raised when the picture is sent to the server asynchronously.
startCapture: when called, starts displaying the output of the camera in real time;
stopCapture: pauses the update of the camera;
takeSnapshot: takes a snapshot of the current camera output (as visible on screen) and sends it asynchronously to the server, raising the PictureTaken event.
When the startCapture method is called, the PictureSnapshot control (or, better, its underlying VIDEO tag) starts displaying whatever the camera is pointing to (if we so authorize it).
Here is an example of one of my home walls… yes, I deliberately got out of the way!
OK, enough talk, the code for PictureSnapshot looks like this:
As you can see, it inherits from WebControl. This is the simplest class in ASP.NET that allows me to output the tag I want, and also includes some nice stuff (width, height, style, class, etc). Also, it implements ICallbackEventHandler for the client callback stuff.
You may find it strange that I am setting explicitly the WIDTH and HEIGHT attributes, that is because VIDEO requires it in the tag, not just on the STYLE. In the way, I am removing any CROSSORIGIN, SRC, MUTED, PRELOAD, LOOP, AUTOPLAY, MEDIAGROUP, POSTER and CONTROLS attributes that may be present in the markup, because we don’t really want them.
The PictureTakenEventArgs class:
Finally, a simple event handler for PictureTaken:
Pictures arrive as instances of the Image class, and you can do whatever you want with it.
As always, feedback is greatly appreciated!
Continuing with my quest for reusable, no dependencies, Web Forms AJAX controls, this time I wanted a replacement for the venerable UpdatePanel control. Specifically, I wanted to address the following issues:
- Allow the partial update of a region on my page, including all of its controls;
- Have the ability to only send data for controls living inside my control, not everything else on the page (read, __VIEWSTATE);
I ended up with a CallbackPanel control, which is what I am going to talk about. Here is its declaration:
The CallbackPanel control supports some properties:
SendAllData: if all the data in the form should be sent, including viewstate, or just the data for the controls inside the CallbackPanel (default is false);
For causing an update, we call its callback function, passing it a parameter and an optional context:
The most important property in CallbackPanel is the server-side event, OnCallback: this is raised whenever the callback function is called:
This event receives a CallbackEventArgs argument, which is nothing more than:
And finally, the code for the CallbackPanel itself:
Again, it is implementing ICallbackEventHandler, for client callbacks, but this time it is inheriting from Panel, which is a nice container for other controls. The rest should be self-explanatory, I guess. If you have questions, do send them to me!
As always, hope you like it!
- Set up a control that renders an AUDIO tag;
- Generate a voice sound from the passed text parameter on the server and save it into an in-memory stream;
- Convert the stream’s contents to a Data URI;
- Return the generated Data URI to the client as the response to the client callback.
So, first of all, my markup looks like this:
As you can see, the SpeechSynthesizer control features a few optional properties:
- Age: the age for the generated voice (default is the one of the system’s default language);
- Gender: gender of the generated voice (same default as per Age);
- Culture: the culture of the generated voice (system default);
- Rate: the speaking rate, from –10 (fastest) to 10 (slowest), where the default is 0 (normal rate);
- Ssml: if the text is to be considered SSML or not (default is false);
- Volume: the volume %, between 0 and 100 (default);
- VoiceName: the name of a voice that is installed on the server machine.
The Age, Gender and Culture properties and the VoiceName are exclusive, you either specify one or the other. If you want to know the voices installed on your machine, have a look at the GetInstalledVoices method. If no property is specified, the speech will be synthesized with the operating system’s default (Microsoft Anna on Windows 7, Microsoft Dave, Hazel and Zira on Windows 8, etc). By the way, you can get additional voices, either commercially or for free, just look them up in Google.
Without further delay, here is the code:
As you can see, the SpeechSynthesizer control inherits from HtmlGenericControl, this is the simplest out-of-the-box class that will allow me to render my tag of choice (in this case, AUDIO); by the way, this class requires that I decorate it with a ConstructorNeedsTagAttribute, but you don’t have to worry about it. It implements ICallbackEventHandler for the client callback mechanism. I make sure that all of AUDIO’s attributes are removed from the output, because I don’t want them around.
Inside of it, I have an instance of the SpeechSynthesizer class, the one that will be used to do the actual work. Because this class is disposable, I make sure it is disposed at the end of the control’s life cycle. Based on the parameters being supplied, I either call the SelectVoiceByHints or the SelectVoice methods. One thing to note is, we need to set up a synchronization context, because the SpeechSynthesizer works asynchronously, so that we can wait for its result.
A full markup example would be:
And that’s it! Have fun with speech on your web apps!
I have been playing recently with HTML5, and one thing that I got to understand really well was the new upload mechanisms available. Specifically, I wanted to understand how
SkyOneDrive, Google Drive, Dropbox, etc, all support dropping files from the local machine, and how to use it in an ASP.NET Web Forms (sorry!) project, and I got it!
So, I want to have a panel (a DIV) that allows dropping files from the local machine; I want to be able to filter these files by their content type, maximum length, or by any custom condition. If the dropped files pass all conditions, they are sent asynchronously (read, AJAX) and raise a server-side event. After that, if they are multimedia files, I can preview them on the client-side.
My markup looks like this:
The UploadPanel control inherits from the Panel class, so it can have any of its properties. In this case, I am setting a specific width, height and border, so that it is easier to target.
Out of the box, it supports the following validations:
MaximumFiles: The maximum number of files to drop; if not set, any number is accepted;
MaximumLength: The maximum length of any individual file, in bytes; if not set, any file size is accepted;
ContentTypes: A comma-delimited list of content types; can take a precise content type, such as “image/gif” or a content type part, such as “image/”; if not specified, any content type is accepted.
When a file is dropped into the UploadPanel, the following client-side events are raised:
OnValidationFailure: Raised whenever any of the built-in validations (maximum files, maximum length and content types) fails, for any of the dropped files;
OnBeforeUpload: Raised before the upload starts, and after all built-in validations (maximum files, maximum length and content types) succeed; this gives developers a chance to analyze the files to upload and to optionally cancel the upload, or to add additional custom parameters that will be posted together with the files;
OnUploadFailure: Raised if the upload fails for some reason;
OnUploadCanceled: Raised if the upload is canceled;
OnUploadProgress: Raised possibly several times as the file is being uploaded, providing an indication of the total upload progress;
OnUploadSuccess: Raised when the upload terminates successfully;
OnUploadComplete: Raised when the upload completes, either successfully or not;
OnPreviewFile: Raised for each multimedia file uploaded (images, videos, sound), to allow previewing it on the client-side; the handler function receives the file as a data URL.
The Upload event takes a parameter of type UploadEventArgs which looks like this:
This class receives a list of all the files uploaded and also any custom properties assigned on the OnBeforeUpload event. It also allows the return of a response string, that will be received by the OnUploadSuccess or OnUploadComplete client-side events:
Finally, the code:
The UploadPanel class inherits from Panel and implements ICallbackEventHandler, for client callbacks. If you are curious, the __CALLBACKID, __CALLBACKPARAM, __EVENTTARGET and __EVENTARGUMENT are required for ASP.NET to detect a request as a callback, but only __CALLBACKID needs to be set with the unique id of the UploadPanel control.
HTML5 offers a lot of exciting new features. Stay tuned for some more examples of its integration with ASP.NET!
First, the target markup:
No custom properties whatsoever, just an handler for the AutoFill event, which will be called whenever the fill function is invoked.
The AutoFillDropDownList inherits from DropDownList:
Again, for client callbacks, we need to implement ICallbackEventHandler. In its RaiseCallbackEvent we raise the AutoFill event, store its output in the request itself (HttpContext.Items collection), and on GetCallbackResult, we take this value and pass it to the client.
Another important thing is, whenever there is a postback, we need to raise the AutoFill event again, because the drop down must be in a consistent state, therefore we need to get its items. We do that in the PreLoad event of the page.
The AutoFill event uses a special argument:
Results: the key-value pairs that will be used to fill the drop down list items.
A typical handler might look like this:
There are no dependencies on any external libraries other than Microsoft AJAX Library, which is included by the ScriptManager.
Hope you like it!
I have talked about client callbacks in the past, and even provided a general-purpose control for invoking code on the server-side. This time, I will provide two more examples:
I once had the need to have a button control that would change its look depending on a theme, for example, it would render either as regular button, an image or a link. Of course, the only way I had to achieve this was by manually swapping the Button control for a ImageButton or a LinkButton, which wasn’t really a solution, so I started to think of a control that could do the trick… and here it is!
Basically, I wrote a button control that displays in one of 5 ways:
- A regular button:
- A text hyperlink:
- An image:
- A button with HTML content (see this):
- A hyperlink with HTML content:
In ASP.NET terms, I have a server-side control with a ButtonType property. The markup that produces each effect is as follows:
For Link and Button, if the Template property is not specified, Text will be used for the textual description of the button or link. If instead a Template is available, it will be used instead of the Text. Keep in mind that you can specify almost any HTML you like for the Template, as long as it can be surrounded by an A (in the case of the Link type) or BUTTON (for Button) tags. If no Template is supplied, it will render and behave just like a LinkButton or a Button.
This control implements IButtonControl, so it shares the usual behavior of regular button controls, like having a text property, a validation group, a postback URL, Click and Command events, event bubbling, etc. It uses the control state to save some properties, so it is safe to turn off view state in it.
I almost forgot: here is the code!