Architecture and Database Configuration for a Voice Enabled Survey Application

In a previous post I introduced a new example added to the VoiceModel Project that shows how to create a voice enabled survey application that allows customers to take a survey over the phone.  This sample project uses Entity Framework (EF) 5 as the ORM for persisting the survey meta-data and results.

This solution uses the code-first model where you define your entities as classes first. You will find the entities for this solution in the project Survey.Entities. This solution also uses the Repository Design Pattern to abstract EF to a higher level and allow for easy swapping to another ORM or a mock-up for unit testing.  You will find the code for the Repository in Survey.Repository.  This solution also uses the Fluent API to map the entities to the database schema; setting the primary and foreign keys, as well as the SQL types to store the entity properties in. You will find this configuration in Survey.Repository.ModelConfiguration. To handle transactions this solution uses the Unit of Work Design Pattern. The definition for the Unit of Work can also be found in Survey.Repository. And finally, there is a Service Layer that handles the domain logic and returns data transfer objects (DTO) to the voice application. So the architecture for this solution looks like this:


The sample application uses a drop-create approach for database migration since it is basically a test application. This means that the database drops any existing database when the application is started and creates a new one. So how does the database have any test data in it?  By using a database initializer that seeds the data when the database is created.  The database initializer is located with the voice application, which is in the Survey.Voice project.  The name of the database initializer is DBInitializer and here is the code for it.

    public class DBInitializer : DropCreateDatabaseAlways<surveycontext>
    {
        protected override void Seed(SurveyContext context)
        {
            UnitOfWork uow = new UnitOfWork();
           string surveyName = "MySurvey";
            Entities.Survey survey = new Entities.Survey()
            {
                Name = surveyName,
                Questions = new List<question>()
            };
            survey.Questions.Add(new Question()
            {
                AnswerType = AnswerTypes.boolean,
                Sequence = 1,
                Text = "Do you like this question?"
            });
            List<possibleanswer> answers = new List<possibleanswer>();
            answers.Add(new PossibleAnswer()
            {
                Answer = "oranges",
                Sequence = 1
            });
            answers.Add(new PossibleAnswer()
            {
                Answer = "apples",
                Sequence = 2
            });

            survey.Questions.Add(new Question()
            {
                AnswerType = AnswerTypes.list,
                Sequence = 2,
                Text = "Which do you prefer, oranges or apples?",
                PossibleAnswers = answers
            });

            uow.SurveyRepository.Insert(survey);
            uow.Save();

            User user = new User()
            {
                Name = "Joe Tester",
                UserId = "001",
                Pin = "002"
            };
            uow.UserRepository.Insert(user);
            uow.Save();

        }
    }

This code seeds the database with two survey questions and a user. Notice that it inherits from DropCreateDatabaseAlways.  This ensures that the database is created anew at each application start, as mentioned previously.  If we were putting this into production we would use another type of database migration so that the database would not be lost every time the application starts, but this works great for testing. If you wanted to play around with your own defined survey this is where you can modify the code to do so.  In production we may not want to seed any data and provide a web application to configure the surveys.  In that case we would just leave the Seed method empty.

We have to tell EF what database initializer to use, and that is set in the Global.asax on application startup.  Here is what the code looks like for that.

       protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            VoiceViewEngine.Register(ViewEngines.Engines);

            //Initialize database for test web application
            Database.SetInitializer(new DBInitializer());
            SurveyContext context = new SurveyContext();
            //Need to invoke context to have the DbInitializer do its stuff
            context.Surveys.Find(-1);

        }

This provides an overview of the architecture used in this voice enabled survey application and how the database is configured and seeded. In an upcoming post we will look at the details of how the voice application is defined.


Comments

Popular posts from this blog

Using Claims in ASP.NET Identity

Seeding & Customizing ASP.NET MVC SimpleMembership

Customizing Claims for Authorization in ASP.NET Core 2.0