(ASP.NET) How create master UserControl

There are cases when you want your ASP.NET usercontrols all look the same. For example, to add a header and footer to all your popup, and these header-footer needs always looks the same.

You know you can do it by creating a header.ascx footer.ascx, then add them in all your UC. But, you will still need to maintain all the containers for these, and keep them in sync.

You want it to be as easy as using masterPages + web form.

I had to do that recently, I searched for solutions. I only found complicated solution involving inheritance and lot of code behind script.

But now, I have working solution, that uses real contentplaceholders, and absolutely no code behind.

The only prerequisites is that you need to load these userControl from Ajax. You can’t add directly on another page, as you did with a normal usercontrol.

My solution is to just use the standard master page / asp.net webform!

When you create a masterPage, it is filled with all page content: html, head, body, form, … and all the stuff required for viewState to work. But, you can delete all that content.

Create your masterUserControl, let’s call it popup.master. In Visual Studio, just create a normal MasterPage.

By default, it is filled with that content:

<%@ Master Language="VB" CodeFile="popup.master.vb" Inherits="ucTest_popup" %>
<!DOCTYPE html>
<html>
<head runat="server">
    <title></title>
    <asp:ContentPlaceHolder id="head" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
        
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>

But, you don’t create a page, you create a master for your userControls.  So. remove all page-related content, and only add your common usercontrol html.  It will look like this:

<%@ Master Language="VB" CodeFile="popup.master.vb" Inherits="ucTest_popup" %>
<div>
   <header>My common header</header>
      <article>
         <asp:contentplaceholder id="cph1" runat="server">
         </asp:contentplaceholder>
      </article>
   <footer>My Common Footer</footer>
</div>

The designer indicates an error on the asp:contentplaceholder item, but just ignore it.

Then, create some popup, as asp.net webpages, and select that popup.master.

Add specific code in the contentPlaceHolder:

<asp:Content ID="Content1" ContentPlaceHolderID="cph1" Runat="Server">
   Popup1 Content
</asp:Content>

You can now test that page directly in your browser, and look at its source: It contains only the html of the master embedded with your specific content.

<div>
   <header>My common header</header>
   <article>
      Popup1 Content
   </article>
   <footer>My Common Footer</footer>
</div>

Finally, to use it in your app, you will need to load it from ajax, because you can’t add it directly like a normal usercontrol.

A simple jquery call can do the job:

$('#myDiv').load("/popup/popup1.aspx")

The “myDiv” div now contains the userControl + master html! Just use your favorite popup manager to show it now, e.g.

$('#myDiv').kendoWindow({}).center().show()

Happy coding with these “master usercontrol”!

How to use Try Catch in ASP Classic

The worst part of Classic ASP in VBScript is Error Handling.

You need to type “on error resume next”, then, check, on every line, check if the previous one generates an error using [If Err.Number <> 0 then …]. That’s a real pain.

When you need solid error handling inside an ASP – VBScript sub or function, there’s a very simple method you can apply.

Just turn your existing error-handling-needed function into JavaScript, and use Try-Catch!
What? Javascript in ASP Classic?
Yes you can! It’s called JScript, it’s ECMAScript 3 compatible, and it just works.

Also, it’s totally compatible with your existing VBScript application, that will be able to call that JS method without any issue.  Even all your application VBScript variables will be shared between VB and JS.

Sample:
100% VBScript file:

<%
function fct1
	fct1 = true
	on error resume next
	' do something that can crash
	dim i : i = 1
	i = i / 0
	if err.number <> 0 then
		fct1 = false
		response.write err.number & "<br>"
		response.write err.description & "<br>"
	end if
	on error goto 0
end function

sub sub1
	dim value : value = fct1()
	response.write "result: " & value
end sub

call sub1()
%>

Now, the same, using mixed VBScript/ Javascript

<script runat="server" language="javascript"> 
function fct1(){
	try{
		// do something that can crash 
		var i = 1;
		i = parseINT(i); // <- typo
		return true;
	}
	catch(e){
		Response.Write(e.message);
		return false;
	}
}
</script>
<%
sub sub1
	dim value : value = fct1()
	response.write value
end sub

call sub1()
%>

Now, go and start converting your Classic ASP functions in JavaScript!
Just, watch out as JScript is case sensitive, VBScript is not.
vb: response.write "txt"
js: Response.Write("txt");

 

How to mix Classic ASP and Server-Side Javascript

Sometimes I need to fix some old Classic ASP applications or add small new features to them.

Because I do Javascript or C# every day for new apps, it hurts to get back to VBScript for these old apps!

That’s why I try to do these using Server-Side Javascript instead.  But wait, how can I mix NodeJS and VBScript?  The answer is, you can’t.  But, there was Server-Side JS before NodeJS exists!

Now, look at this.

You have a ASP Classic site like this:

<body>
<% dim product : product = "apple"
response.write product %>
...

And you need to create a new function to get the product name.

But, you don’t want to do it in VBScript, because you prefer JavaScript.

All you need to do is to create an “include” file, in pure javascript, like this:

includeJS.inc:

function getProduct(){
	var product = "banana";
	return product;
}

And, add it to your existing ASP file:

<script runat="server" language="javascript" src="includeJS.js" ></script>

Finally, you can fix your existing code like this:

<% dim product : product = getProduct()
response.write product %>

Yes, the VB code can call JS function directly.
Also, your JS code can also use already existing VBScript functions and variables.

(edit 2020-12-23) I just added a working sample for this, that you can download, including web.config “urlrewrite” to keep your js-code hidden from browser direct call.

IIS can run Server-Side Javascript since 1997

When I read articles about NodeJS, they almost all consider NodeJS like if Ryan Dahl invented Server-Side Javascript.

But, did you know that, in IIS 3.0 on Windows NT 4.0, it was possible to run server-side javascript?

On May 15, 1997, Microsoft released the Service Pack 3 of Windows NT4, introducing Active Server Page technology (ASP).

Classic ASP was built to run Active Script.  VBScript AND JScript are the first Active Script languages developped, and were included in all versions of Windows since 95.  And, that “Jscript”, can be used to run server-side javascript.

Wait, JScript is not JavaScript?  Yes it is. Just another name.  FireFox 1.0 run something named JavaScript 1.5, and IE6 run JScript 5.0  And, both were, in fact, ECMAScript 3.0. (more info)

That said, it means that if you still need to work with Classic ASP application, to maintain old software that can’t be rewritten, you can write some JavaScript to do that.  And, it is totally compatible with existing VBScript app!

Now, look at this sample of a 100% server-side javascript in an classic ASP file.

I’ll show you, in another article, how you can add some javascript in your existing Classic ASP / VBscript application.

How to decode a base64 string in VB.NET

Sometimes, we receive an e-mail that we can’t really open directly, but we have the base64 source.

I may receive an attached EML file, that is, an outlook express email attached with another e-mail.

I have all the original source of this file, but I do not have Outlook Express installed.

So, I created a really simple decoder and it work fine.  You just have to look at the boundary of your email.  Find the beginning of attachment by searching for “filename=” and you’ll have the filename of the attached file.

Then, copy the following code, all the “binary string” code, and only this, without the leading MIME informations, to a text file.  In my sample, I called it “c:base64.txt”.  Then, I saw that the filename is a pdf.  I choose “c:base64.pdf” as my output.

This is the code you can use to decode a base64 attachment.

   Dim bytes() As Byte
   Dim reader As New System.IO.StreamReader("c:base64.txt")
   Dim str As String = reader.ReadToEnd
   reader.Close()
   reader.Dispose()
   bytes = System.Convert.FromBase64String(str)
   Dim writer As New System.IO.BinaryWriter(IO.File.Open("c:base64.pdf", IO.FileMode.Create))
   writer.Write(bytes)
   writer.Close()
That’s all!

How to get response headers on all jquery ajax requests

REST / Ajax querie are part of our day as a web developer.

Recently, we had to handle response headers (when communicating with Basecamp3 API).

The default jqXHR object is not very helpful to give us a beautiful list of all response headers.

There are 2 functions available:

  • getResponseHeader(key…) that returns the value of that key, but you need to know which one you need.
  • getAllResponseHeaders, that returns a “string” of all headers, in key-value pair, but all stuck in 1 big string.

Solution

So, we create something that is, on every call, parsing that string and set it in a easy-to-use object embedded to the jqXHR.

$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
  jqXHR.done(function (results, responseText, jqXHR) {
    getResponseHeaders(jqXHR);
  })
}

function getResponseHeaders(jqXHR){
  jqXHR.responseHeaders = {};
  var headers = jqXHR.getAllResponseHeaders();
  headers = headers.split("\n");
  headers.forEach(function (header) {
    header = header.split(": ");
    var key = header.shift();
    if (key.length == 0) return
    // chrome60+ force lowercase, other browsers can be different
    key = key.toLowerCase(); 
    jqXHR.responseHeaders[key] = header.join(": ");
  });
}

Now, you can get, jqXHR.responseHeaders.etag value directly. (lowercase)

Because the “.done” set in ajaxPreFilter is set before the one of the caller, we can fill the responseHeaders property on all call.  And, when the caller gets its .done event executed, that third parameter, jqXHR, contains the responseHeaders already filled.

Warning

You will be able to retrieve these headers, if you do same-domain query.  For cross-domain queries, the server needs to return that header: Access-Control-Expose-Headers (more details)

How to fix DNS CAA issue on SSL Labs Test

You ran the SSL Labs Analyzer on your domain name, and you got a DNS CAA Issue.  You want to solve it, because your goal is to get the A+ Rating from Qualys.

How to fix that?

You need to add a CAA Entry in your DNS.

What is a CAA DNS entry?

That entry tells which certificate authority delivered your SSL certificate.  If someone hack your ssl certificates with certs not in your liste of “known” providers, it will be an indication that your site may have been modified by someone else.

The blog you currently read is hosted on AWS EC2 infrastructure.  The DNS is sold and managed by AWS Route 53 services, and we got our SSL certificates free from Letsencrypt.

So, I’ll explain you how enable your CAA DNS setting based on these prerequisites.  The procedure is the same for any other SSL seller and DNS service.

Step-by-step configuration

  • In your Route 53 console:
    • select your domain name
    • Click “Create Record Set”
      • Leave name empty
      • Choose type: CAA
      • Enter value, in my case it was:
        [0 issue “letsencrypt.org”] (without brackets)

In addition, you can use that generator: https://sslmate.com/caa/ to obtain your value.
From that generator, just enter your domain name.
Next, click “Auto Generate Policy”.
The tool will look at your current SSL certificate.  Then, it will give you the desired value you should type in your CAA DNS entry.

Finally, wait a little for DNS propagation, and run the test again, and you will get a nice green status on your CAA test!

You can also test your CAA with that tool:
https://caatest.co.uk/

Make your api faster with ThreadPool in ASP.NET

One easy way to make a server-side call faster, in your API, is to add some async procedures.  Sometimes, you want to call an external api (e.g. mailchimp…) or just send an e-mail, write a log, etc.

When your API client don’t need interaction from these calls, you can process them asynchronously.

The easiest way to add an async call is from the System.Threading.ThreadPool workspace.

As they say on their documentation, “The thread pool enables you to use threads more efficiently by providing your application with a pool of worker threads that are managed by the system.

And, it’s very easy to use.  This is a very simple example, in VB.NET:

Threading.ThreadPool.QueueUserWorkItem(
   sub
      ' Enter your async procedure here, 
      ' with callback and error handling if needed
   end sub)

That’s all!
That anonymous sub can access your caller parameters and other variables declared outside.

How to build your solutions without Visual Studio installed

I have a small AWS EC2 Windows instance that I use for my personal usage, like hosting that blog.

When I create some small projects at home in Visual Studio 2017 Community, this is how I am able to build them on my server without installing Visual Studio on it.

First, you need to get the latest msbuild.
You can get it from Visual Studio 2017 download page.  On the bottom, click “Other Tools and Frameworks”, then choose “Build Tools for Visual Studio 2017”.
Direct download link

Start that setup file (vs_buildtools_xxx.exe), and choose “Web Development Build Tools”.

After installing, you will get a new command prompt in the start menu, called “Developer Command Prompt for VS 2017”.  Use it to start your command prompt, as it will add to path all required folders to run msbuild from anywhere.

Go to your folder with your solution sln file, and just type msbuild.  It will automatically start building the sln files.

If you use nuget packages, you will get errors about missing packages.  You may have read somewhere that you only need to type “msbuild /t:restore”, but I think that it’s only works for .NET Core solutions, it does nothing for Studio 2017 classic framework projects.

Now you need an additional file: nuget.exe, that you can find there: https://dist.nuget.org/

I use the latest version, 4.1.  The download is not a setup, it’s directly the nuget executable.  Only 1 file is needed.

I suggest to save it somewhere available in your path from DOS, maybe at the same place that msbuild was installed, [C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin].

Now, get back to your sln folder, and just type “nuget restore”.  The “packages” folder will be created, and required nuget packages downloaded there.

You’re ready to try msbuild again.

Wow, it just works!
That was that easy.

 

How to track your server-server call in Fiddler

Telerik Fiddler is the web developer’s best friend.

It does a wonderful job of telling you why it worked, or not.  Its ability to edit and replay some requests is wonderful.  That, with Advanced REST Client, both help you accomplish your day to day job.

It tracks everything.
Almost.
Sometimes, you need to track server-to-server requests.  Example, if your app calls your back-end api, and then, your server needs to call Mandrill API to send an email to your customer.

By default, Fiddler is not tracking that request, that goes out from your server-side app. But, there’s a solution.

In fact, Fiddler track all web traffic generated by “you”, the user currently logged, and who started the fiddler app.

Now, knowing that, all you need to do, is make your IIS Pool run at your name.

By default, IIS uses “ApplicationPoolIdentity” user, it’s a kind of virtual user generated by the web engine, to run the app.  Each pool have its own username.

But, you can change it to something else.

Open IIS.  Go to the Application Pools section. Choose your app pool, then open Advanced Settings / Identity.  Click the dots, choose Custom account, enter your credentials, and you’re done!

Now, your outgoing server-side calls from your back-end can be tracked in Fiddler!