11

I have an ASP.NET MVC solution, and I have a large number of HtmlHelper classes inside the ASP.NET MVC project that take data and generate various snippets of html to display on various pages.

I now have to run a bunch of scheduled jobs and many of those jobs generate emails. I moved all of these jobs into a separate project in the solution (called AdminJob.csproj), but I now find that I have to generate a number of email with very similar HTML as I have in my view pages. I am trying to keep the admin jobs from having a dependency on the ASP.NET MVC project (as I would like to run the adminjob project as a command line if required), and I also want to avoid having my ASP.NET MVC project having a dependency on the AdminJob project (as that just seems odd).

Any suggestions on how I can avoid duplicating the same HTML rendering code in both my ASP.NET MVC project and my AdminJob project?

The only thing I can think about is creating another project in the solution called "ViewHelpers" or something like that and move all of my HTMLHelpers into that project so it can be referenced by both my MVC project and the AdminJob project. It seems a bit overkill to have a separate project just for this code, but I can't think of another solution that doesn't create duplication.

Any other suggestions for a better way to do this and avoid any duplication?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
leora
  • 188,729
  • 360
  • 878
  • 1,366
  • Your suggestion seems logical. This question is primarily opinion-based however and would be interpreted as off-topic. – Nkosi Jan 17 '17 at 01:08
  • I disagree that this is completely opinion based as I am looking for best practice here and it seems like a common situation where you have both MVC view and email generation with overlapping requirements so I would think there are evidence and principal based answers given separation of concerns and other goals. Any suggestions for some thing to change in the question to make you think it would be less off topic? – leora Jan 17 '17 at 01:17
  • I would go as you suggested, creating a separate project for shared code. But don't create it as "SharedHTML" or anything like that, eventually more code that should be shared will show up, and you can use this project for all of that. – Dinei Jan 19 '17 at 02:27
  • May be one other option (if you dont want to have the views shared) is to make a http call to the mvc action from the email utility to get the html. – Developer Jan 19 '17 at 02:35
  • Is your HTML embedded inside your code? – Jacques Jan 20 '17 at 08:36

3 Answers3

6

The way I look at this is that the email is a view type.There are several view types in my web apps (html, email, pdf, rss etc). There are several implementations of this pattern: ActionMailer in ruby on rails or its port to asp.net: MvcMailer.

This way you can take full advantage of the Razor engine in both your web application and your emails in order to reduce duplication.

You can host your views in another project and inform your ViewEngine about where to look for the views (see Views in separate assemblies in ASP.NET MVC). I find this to be overkill.

Another way - the one I use - is to have the email templates in the same project with other views.

If you want to render the views outside of a web application you can compile the razor templates in a console app using one of these:

Community
  • 1
  • 1
dexter
  • 1,217
  • 9
  • 12
1

Don't completely rule out the idea of having the AdminJob depend on the website. This might work for you: How to use Razor View Engine in a console application?.

Note that the AdminJob having a compile-time dependency on the MVC project does not prevent the AdminJob running as a console app. That can work fine.

The problem I would expect — even if you move View-related stuff out into a shared project— is that you may find that it all breaks at runtime when running outside of the website. Under the hood, there are dependencies on System.Web stuff, e.g. HttpContext, which will be null at runtime. Some dependencies can be stubbed, some can't.

Being in a separate shared project won't fix this problem at all, so I don't think moving code about gains anything.

But the typical approach (i.e. 5 out of last 6 companies I've worked for) here is:

Forget the command line idea. Make the Admin tool part of the website. Whatever you think you wanted to run from the command line, run it from a push button on the admin tool instead.

PS

“Email with very similar HTML as in my view pages” is a knot you should cut.

Either it is, or can be, identical to the view pages, in which case you want the AdminJob to reuse the view pages; or it isn't. In which case the AdminJob should have its own HTML. In this second case, take the line that there is no such thing as 'similar' HTML; if it's not the same, it's different.

Community
  • 1
  • 1
Chris F Carroll
  • 11,146
  • 3
  • 53
  • 61
0

I understand the temptation to reuse the html from regular website pages into your email engine. However, I think that's a good example of over-engineering. That will create much more limitations long-run than the benefits you have short-run.

Think about couple of things:

HTML for emails is by design different from HTML for pages. Even though today they look similar, tomorrow they will look different. You just said it - 'email with very similar HTML as i have in my view pages', you didn't say 'with exact same HTML'.

HTML for email should not have any advanced HTML or any JavaScript in it. It should ideally have inline CSS and no JavaScript. The CSS compatible with email clients is very limited. Markup rules differ from the natural and modern way of writing it for regular browsers. Good example is email clients being friendly with tables, while in modern web you rarely use tables nowadays, especially if you want to stay responsive (cross-screen-platform-browser). Read about all limitations here: email-standards.org

HTML for modern web does not have to be so static as email message has to be.

These all reasons are the idea behind popular commercial email senders online. They help you create an email distribution list and they take the headache to generate the proper limited HTML on their shoulders. Otherwise, would would they exist? anybody could send group emails if not the markup differences.

My conclusion from all this: if you decide to use your web page markup for the emails, you are limiting both. You are over-engineering. It will be much simpler if you don't reuse the regular page markup into your email messages. I understand they are similar today, but they may not be tomorrow.

Obviously, it's a good idea to have templating capabilities for your email engine (has nothing to do with reusing web pages markup). For that you could use any of the existing templating engines, or you could quickly write yours (after all, dirty string.Replace() will replace placeholder with the value if you have HTML message template as string, loaded from file or database).

In other words, to directly answer your question: don't hesitate to diverge the two paths of web pages and emails. Avoid sharing capabilities, as they mostly differ. Consider the two in isolation from each-other.

Tengiz
  • 8,011
  • 30
  • 39