Module Design Considerations
Now that you have your bearings and you know what you want to accomplish with the module, let's look at some aspects that will have an influence on how you will code this. What follows are a number of decision points you will come across while you're moving from your module's concept to code.
3 Tier Design and MVC
By far the most common architecture in ASP.NET Web Forms in the 3-tiered approach where you have a presentation layer, a business layer and a data access layer (DAL). This approach also pervades the DNN Platform. The idea is to separate your code between these 3 layers so that it becomes easier to make changes in one layer without affecting any others. This makes the solution easier to maintain. Concretely the ascx files and their code behind would constitute the presentation layer code, the Sql methods the data layer and the various controllers and objects the business layer. In DNN you'll find the entire data layer under the namespace DotNetNuke.Data.
But as simple as it sounds, it's as difficult to keep consistent and Web Forms has been faulted by many for not encouraging developers enough to keep their code well separated. MVC is seen as a logical progression in web development and it claims to provide an ever better "separation of concerns". DNN 7.5 is slated to provide support for modules that wish to follow this programming paradigm. A full discussion of the merits of MVC falls outside the scope of this book, however, and given that support for MVC has not yet been implemented in DNN as of this writing, I will focus on a 3-tier approach in the remainder of this chapter. Keep in mind that this is a totally valid way of creating your modules.
DAL
The Data Access Layer is probably the easiest layer to recognize in any DNN module (and DNN itself). And again we've seen significant changes in the technical landscape since DNN was first created. The DAL is responsible for persisting the objects of our application to some data store. Or to put it more simply: it stores the various records in the various database tables of our application and can retrieve those again.
Because DNN was designed to be very flexible and extensible, many parts were designed following the provider model pattern. Basically you have an abstract class defining a number of abstract methods and then you have a concrete implementation of the class which is constructed by some factory method at runtime. This allows DNN to support other databases than SQL Server like MySQL or Oracle. If you wanted to have DNN run on Oracle all you'd need to do is to create the concrete class that implements all the defined methods and you'd need to create the various scripts to create the correct database schema in Oracle. This has actually been done in the past and it was a commercial project. But it's an enormous undertaking with limited benefits. What turned out to be the biggest stumbling block is that it needed to be repeated for each and every module you had if you wished to run your DNN on Oracle. So more and more it is assumed that you are using DNN on SQL Server, especially since SQL Server has been accepted as a enterprise grade database and since there are free entry level versions of this. But you'll see the legacy of this in the naming of some parts. Like the .SqlDataProvider filename extension for the scripts for SQL Server. As you can imagine the Oracle provider had .OracleDataProvider files.
This development is why DNN has been moving away from the provider pattern for a while now. The above is dubbed the DAL 1. The first move was to add generic methods in the data provider that allowed module developers to avoid having to code the data provider abstract class and sql data provider implementation in their own code for each and every function. Instead you could code you method directly calling a specific stored procedure. This mechanism is referred to as DAL +.
There are two developments in the data access domain since the original DNN that have had significant impact on ASP.NET in general and the way DNN interacts with data specifically: ORM and LINQ. To start with the latter, LINQ is a set of extensions to the .NET languages allowing developers to make SQL-like queries of various collection types (arrays, dictionaries, etc). It has become hugely popular since its introduction in .NET 3.5. There are many good resources on LINQ and I will assume you are familiar with it. ORMs, or Object Relational Model mappers in full, remove the repetitive task for developers of creating CRUD (Create, Read, Update, Delete) statements for their objects between their code and the database. Instead the developer can hand over an object and tell the ORM "just store this" and the ORM will craft the SQL dynamically to make this happen. ORMs like Microsoft's Entity Framework can be an incredibly powerful tool and time winner for developers. But there are a few downsides to this. First you'll need to extensively decorate your code to make sure the ORM does exactly what you want it to. Then there is obviously a performance penalty. And finally you'll have a dependency on a component that is not yours. Especially the latter two points make it less than ideal for the module developer who wishes to redistribute. You'd be forced to redistribute the ORM along with your module. Instead, DNN has chosen to adopt a so-called Micro-ORM. A Micro-ORM is not quite as powerful as a full ORM, but what you lose in flexibility you get back in performance.
DNN 7 ships with PetaPoco and introduces a new way of doing data access: DAL 2. This new layer promises to cut down the number of lines of code that module developers need to create significantly. The DAL 2 is discussed more in depth in the DAL chapter of this book.
Client-side vs Server-side
Back in 2001 when ASP.NET was first released, the thinking was still very much thin client. Browsers were pretty dumb, buggy (IE) and non-standardized (again IE) so the best approach a developer could take was to do as much as possible on the server and limit what the browser did to just displaying HTML and sending back form data. This worked for a number of years until it was discovered that with Javascript you could alter the contents of a page and do similar interactions to the server as what the browser does when posting back eliminating the need for page postbacks. Ajax was born and soon every developer was asked to provide solutions that didn't require page refreshes any more. Microsoft released its own version of Ajax in ASP.NET using so-called update panels. Skip a few years and we see the emergence of jQuery and JSON. These two technologies make it trivially easy for developers to send data back and forth to the server and alter what is on screen. And it beats Microsoft's solution on two very important aspects: load and performance. Update panels send back the whole page to the server and the server responds with bulky HTML. This means that there are a lot of bytes going back and forth. With the more modern approach the developer decides selectively what is being sent back and forth, making this a much more efficient affair. Fast forward a few more years and Microsoft launches WebAPI which is intended to make developing services for data exchange between a web page and the server a lot easier. This has unlocked the full potential of jQuery/JSON for ASP.NET developers.
DNN 7 includes enhanced support for jQuery (you'll find the libraries under Resources/Libraries), JSON (DNN ships with the most popular Newtonsoft.Json.dll library) and WebAPI. Details will be explained in another chapter in this book. What you should think about at this stage of your project, though, is how you will divide the work your module does. What is best done on the server and what will you do using services or even plainly in Javascript? Browsers are much better behaved these days and you are expected to provide a smooth experience on both high-bandwidth as well as low-bandwidth (read: mobile) connections. Naturally you will need to keep security in mind, too. Services can be exploited and every door you open on the server for your application is one more target for a hacker.
Localization
For those of us that live outside the US it is all too familiar to see some new technological development only to find out that it is US English only. Or that it can't be used in a multilingual setting. This is not ill will, but more of a blind spot of many developers. "It works for me". For years I have been involved in a team of people (mostly from Europe) that tries to identify internationalization issues in DNN and offer solutions for these. This team meets regularly and if there is one takeaway from these meetings it's that this is hard to do right especially if it was not taken into account at the very conception. Besides the obvious translation of texts we see on screen there are differences in how we write numbers, dates and even the direction we write. Making an application that behaves in the same way in all cultures is a daunting task. So I urge you not to underestimate this aspect of your module.
Technically we discern between two types of localization: static- and content localization. The former deals with the texts and graphics that we ship with our work such as buttons ("Submit", "Cancel", etc), field texts ("First Name"), help texts, etc. Static localization is done through resource files. These are XML files with the .resx extension you'll find in the App_LocalResources folders everywhere. These files consist of key-value pairs where the value is the text in one specific language for that file. The US English text is in the file that is simply named MyControl.ascx.resx that you create and supply with your work. Then, if it needs to be translated to French, all a translator would need to do is to create a resource file called MyControl.ascx.fr-FR.resx (fr-FR stands for French as it's spoken in France as opposed to fr-CA which is French as it's spoken in Canada) with the French translations in it. DNN checks the user's browser settings and personal preferences to determine which languages the user prefers and then attempts to find the best match for each text on display. This process includes so-called fallbacks where one could specify that if the user is German speaking from Austria but no text can be found in de-AT then maybe the system should look for the German file for Germany (de-DE) before falling back on US English. As you can probably understand, this can get incredibly complex very quickly. And I hadn't even mentioned we also support overrides per portal and at host level. To keep this from totally bringing DNN to its knees a lot of caching is taking place.
DNN Software provides the resx files for the entire DNN Platform for 5 languages besides English: Spanish, German, Italian, French and Dutch. But with some simple tools you can create your own translation for DNN if you need to. You can use the built-in editor in DNN through the languages page or you can use an external tool like the DNN Translator that you can find on CodePlex. Resource files are normally zipped up into language packs. An example is the aforementioned core language pack. But you can also have module specific language packs. As a module developer you may need to ask a translator to translate your resource files as a service for your customers so you can deliver these packs yourself.
For the most part your concern with static localization means you use the ResourceKey attribute on your controls and add the key to the corresponding resx file. There should be a big red warning light on your monitor that flashes every time you are hard coding any bit of text to display to an end user. It just isn't done. This is not your only concern, but there is a more in depth discussion of localization in another chapter of this book.
Content localization is the domain of multilingual sites. It concerns all the features built into DNN to allow users to create content in different languages and have the site adapt to the user's preferences. The way it is implemented in DNN is that when a page has been designated to be multi lingual it in fact creates shadow copies of itself for the other languages that the portal wishes to support. It then copies all modules from the original page to those shadow pages. At this point translators can work on those modules translating their content and when done they will mark a page as done and it will become available in the site. Sometimes you might not want to have a copy of module, but rather the same one. That is also possible in DNN. You can manage that on the languages interface for a page. What you should be aware of as a module developer is the mechanism described above. Depending on your application you may (a) totally ignore the whole content localization aspect, (b) decide that for other languages the module should be copied as discrete instances, or (c) that your module should not be exploded into n versions but that the same module should appear on each page. In the latter case we'd speak of a module that implements content localization within itself. In the second case we let DNN handle content localization.
Note
This is an extract from the Wrox book Professional DNN 7 by Shaun Walker et al. Copyright remains with P.A. Donker and Wiley Publishers.