1

Got a fairly large web application in asp.net using C#. Also have a mobile setup using a common api that we wrote to basically share data across both of our apps using web methods and common classes.

Email was initially thrown together in maybe two days using a simple email class and some basic properties.

For instance, once a record is created we send an email. Imagine a crm type system such that when an account or a customer is created an email is sent. The thing I dislike the most is we're calling it right from within for instance the presentation layer:

MyAPI.SaveCompany(company object);
Email.SendMail(...);

For the mobile application we've got a web service to for instance save a company just like above. Then just as shown above after saving a company we do the same thing Email.SendMail right within the web method.

Its time to fix this as to me it just feels wrong. What do you guys recommend I do?

  • Should this be a standalone service that sends emails based on events in a database table that keeps track of all these events,

  • Or should I just create an email class like I already have and just call it somewhere else?

I thought about just calling it right when I call SaveCompany (inside this method) and then I wouldn't have to worry about my web UI or my mobile since its inside SaveCompany it would call it automatically. But then this feels wrong as it ties up my manager class (my API) to some physical email implementation.

Can someone please give me some hints or how they accomplish this possibly a look at their design or thought process.

As mentioned this is ASP.NET Web Forms, C#, a lot of jQuery, and SQL Server 2008.

  • Throw an event instead of calling directly. So raise the event: CompanyCreated. Let event listeners attach to it and handle the event. They become decoupled and you can easily attach multiple, for example: SendEmailListeren, SendIphoneNotificationListener etcetera. – Luc Franken Sep 25 '14 at 16:12
  • Luc, please post that as an answer. – JBRWilkinson Sep 25 '14 at 17:23
8
+50

Basically, you have two issues here:

  • E-mails are dispatched from presentation layer,
  • The API is tied up to physical e-mail implementation.

The first issue is solved by the first step of moving the code where it belongs: in business layer. You shouldn't save companies from presentation layer, and you shouldn't send e-mails from there: move all this code where it belongs to, and focus presentation layer on presentation, i.e. generation of HTML code or JSON or XML from a model.

Business layer:

public class Example
{
    public void ProcessSamplePage(...)
    {
        CustomerManagement.Create(...);
        SmtpService.NotifyCustomerRegistered(...);
        var model = ...
        Presentation.GenerateHtml(model);
    }
}

Moving from ASP.NET to ASP.NET MVC may help avoiding such errors in future.

The next step is Dependency Injection, which also solves the second problem. Instead of using a specific class provided by .NET Framework to send e-mails directly from your business layer, you can create an interface which will have a specific method for dispatching messages, and then using whatever implementation you want. Dispatching message can mean sending an actual e-mail through .NET Framework, sending an e-mail through a third-party library, sending an e-mail by manually connecting to SMTP server, storing a text file in a directory where the SMTP service will pick it or... storing the message in the database.

Business layer:

public class Example
{
    public Example(IMessagesDispatcher dispatcher) { ... }

    public void ProcessSamplePage(...)
    {
        CustomerManagement.Create(...);
        this.dispatcher.NotifyCustomerRegistered(...);
        var model = ...
        Presentation.GenerateHtml(model);
    }
}

Now that you can store messages in the database instead of just sending them through e-mails, you can imagine more complex scenarios, such as a Windows Service which checks regularly the database and sends pending e-mails. This also allows to control the load of SMTP server: if you have to send hundreds of e-mails per second between 2 PM and 3 PM, but only a few dozen e-mails per minute at night, you can reschedule low-priority e-mails to be actually dispatched at night.

  • Considering i am validating on the client side what benefit would it bring to create the business layer. Would it in this simple example call the save customer data layer method and then send an email right after? So in this case although its only 2 actions i should move this to a busoness layer. – JonH Sep 25 '14 at 17:28
  • What do you mean by "i am validating on the client side"? – Arseni Mourzenko Sep 25 '14 at 17:52
  • Client side validation before submitting my form. What else or what would my business layer need if i am already validating the fields are correct so i should be able to save for instance the company. – JonH Sep 25 '14 at 17:54
  • 2
    So you're validating the fields with JavaScript, but have no server-side validation? Then your top priority concern should be to add server-side validation before your website is hacked. Let me guess, you don't have automated tests where you inject wrong/malicious input values and see how the system behaves either, right? – Arseni Mourzenko Sep 25 '14 at 19:42
  • 1
    I was going to answer this question but I see the answer is here :) I have seen this done this way many times. The poster is correct that stripping out the business logic of the presentation layer is the first step and then using DI to solve the email provider question is the way to go. Storing your email details in a database and having a service to send them ensures that so long as you have called the database that a separate service will send the email, you can do this with straight database persistence or with a database backed queuing technology. – krystan honour Oct 1 '14 at 12:47
2

Depending on your setup, email can occasionally take an unreasonable quantity of time to respond, and it can fail ambiguously and need retries. So I would suggest that this is one of the times when a service is in order. Either in the form of a service of your own, or of an SMTP server you have control over.

The local SMTP server presents a better-known interface, which mediates the other issues, but I generally favor the situation where the status of the database is what causes the sending of messages asynchronously.

The best solution I have seen is for email to be integrated into a workflow service that keeps track of who has done what and whom that enables to do what next. Then you can send email with effective links in them, but know when those links are no longer applicable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.