Click here to Skip to main content
15,885,920 members
Articles / Web Development / ASP.NET
Tip/Trick

Support Desk Day 3 of n

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
29 Dec 2015CPOL5 min read 11.2K   8   1
First Draft. This is day three of a multi day project using ASP.NET Web API for the server and WPF MVVM for the client.

Introduction

For Support Desk, I used Visual Studio 2015 ASP.NET Web API to host a help desk server. It will allow authenticated users to create, edit, and search support tickets, customers, and solutions. The client is in WPF, but any client using HTTP can access the server through Web API allowing the customer to easily customize their client.

Day One and Two

For testing purposes, we created two different solutions on days one and two for the client and server. Open two instances of Visual Studio, with the server solution from day one in one and the client solution from day two in the other. If you didn't follow along through days one and two, you can do it now. Or you can find the source code on CodePlex with the links below.

You can find the day one article here and download the completed project from here on CodePlex.

Download the completed day two source code here on CodePlex. The day two article can be found here.

Day Three

Our support ticket server is going to be available publicly, so we are going to have to add some authentication. So we will register a user, and use those credentials to retrieve an Access Token.

NuGet Packages

The methods we need for HttpClient are in the Microsoft.AspNet.WebApi.Client NuGet package. In Solution Explorer, right click on the project and select "Manage NuGet Packages" then install the Microsoft.AspNet.WebApi.Client and EntityFramework NuGet packages.

Register Binding Model

Let's hop back over to the server solution and compile and run. Debug>>Start Debugging. Let the project home page load, then follow the API link across the top. On day one, we created a Web API project and made some small changes to the ValuesController.

This page is the auto generated documentation for the API. A customer that wants to get our "Hello World!" message could follow the link GET api/Values and see a simple string is returned.

We want to register a user, so follow the POST api/Account/Register link. As you can see, we were given parameters for the RegisterBindingModel that will need to Post to api/Account/Register. It consists of three strings, Email, Password, and ConfirmPassword. There is no UserName, instead use Email for the account.

Now that we know what kind of object the server's expecting us to post, we'll represent it in the client project with a custom class. You can close your browser if it's still open, stop the server project, and switch back to the client. In Solution Explorer, right click on the project>>Add>>New Folder and name it Models. Now right click on the Models folder>>Add>>Class and name the file PublicModels. Visual Studio will add a file called PublicModels.cs into our Models folder with an empty class PublicModels. Rename PublicModels class to RegisterBindingModel and add properties to represent the parameters as follows.

PublicModels.cs

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SupportDeskClient.Models
{
    public class RegisterBindingModel
    {        
        public string ConfirmPassword { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public RegisterBindingModel()
        { }
    }
}

Post RegisterBindingModel

We'll create a login window to register users later, but to get this first user registered, let's just add another method to the constructor of our MainWindow. Modify MainWindow.cs as follows and don't forget the using statement to the Models folder.

C#
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Windows;
using SDCFollowThrough.Models;

namespace SDCFollowThrough
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //GetRunAsync().Wait();
            PostRegisterAsync().Wait();
        }
        public async Task PostRegisterAsync()
        {
            using (var client = new HttpClient())
            {

                //setup login data
                var RegisterData = new RegisterBindingModel();

                RegisterData.Email = "rbass@displaysoft.com";
                RegisterData.Password = "Rb_123456";
                RegisterData.ConfirmPassword = "Rb_123456";

                client.BaseAddress = new Uri("http://localhost:57975/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add
                        (new MediaTypeWithQualityHeaderValue("application/json"));

                var response = client.PostAsJsonAsync<RegisterBindingModel>
                ("api/Account/Register", RegisterData).Result;
                if (response.IsSuccessStatusCode)
                {
                    var GetString = await response.Content.ReadAsStringAsync();
                    var StringResponce = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(GetString);
                    if (StringResponce != null)
                    {
                        MessageBox.Show(StringResponce);
                    }
                }
                //return "new";// TicketView();
            }
        }
        async Task GetRunAsync()
        {
            using (var client = new HttpClient())
            {
                string StringResponce;
                client.BaseAddress = new Uri("http://localhost:57975/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add
                        (new MediaTypeWithQualityHeaderValue("application/json"));

                var response = client.GetAsync("api/Values/").Result;
                if (response.IsSuccessStatusCode)
                {
                    var GetString = await response.Content.ReadAsStringAsync();
                    StringResponce = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(GetString);
                    if (StringResponce != null)
                    {
                        MessageBox.Show(StringResponce);
                    }
                }
            }
        }
    }
}

The using statement lets the compiler look for our RegisterBindingModel class anywhere in the Models folder. Next, we commented out our call to GetRunAsync().Wait() and added a call to our new PostRegisterAsync() and again Wait() because communication with the sever is asynchronous. Followed by our new method PostRegisterAsync and again like our GetRunAsync, everything is wrapped in a using statement to ensure that a connection is closed when the method finishes, regardless of the result of our communication with the server.

After creating a new RegisterBindingModel object RegisterData, I have hard coded an email and a password. The next few lines should be familiar to you from the GetRunAsync explanation from day one. Then responce is set to the Result of client.PostAsJsonAsync<T>, in this case T is our RegisterBindingModel class RegisterData that we send to "api/Account/Register". Then if successful, we will display our string response in a MessageBox.

Support Desk Server

SaveAll on the client and open our server solution back up. We have two changes to make, change our Register response to type string, and setup your connection string which is beyond the scope of the article. You can read more on connection string here. I have SQL's LocalDB installed. If I open the projects' Web.config file, this is what my connection string looks like:

C#
<connectionStrings>
   <add name="DefaultConnection"
   connectionString="Data Source=(LocalDb)\V11.0;
   AttachDbFilename=|DataDirectory|\aspnet-HDSFallowAlong-2015121903515.mdf;
   Initial Catalog=aspnet-HDSFallowAlong-2015121903518;Integrated Security=True"
     providerName="System.Data.SqlClient" />
 </connectionStrings>

In the Controllers Folder, open the AccountController and find the Register method and change it as follows:

C#
// POST api/Account/Register
        [AllowAnonymous]
        [Route("Register")]
        public async Task<string> Register(RegisterBindingModel model)
        {
            if (!ModelState.IsValid)
            {
                return "Fail";
            }

            var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };

            IdentityResult result = await UserManager.CreateAsync(user, model.Password);

            if (!result.Succeeded)
            {
                return "Fail";
            }

            return "Register succeeded.";
        }

Here, I've changed the return type to Task<string> and now return either "Fail" or "Register succeeded." SaveAll and F5>>Start Debugging. Now go back to the client project. We hard coded the username and password that we are going to register, so "Register succeeded." will only be returned once. Start the client F5>>Start Debugging.

Logging In

Stop the client program and add the following class in the Models folder.

C#
public class MyToken
    {
        public string access_token;
    }

Now add using System.Collections.Generic to the MainWindow and the following method.

C#
public async Task PostLogin()
        {
            using (var client = new HttpClient())
            {
                //setup login data
                var RegisterData = new RegisterBindingModel();

                RegisterData.Email = "rbass@displaysoft.com";
                RegisterData.Password = "Rb_6521189";
                RegisterData.ConfirmPassword = "Rb_6521189";

                var formContent = new FormUrlEncodedContent(new[]
                {
                    new KeyValuePair<string, string>("grant_type", "password"),
                    new KeyValuePair<string, string>("username", RegisterData.Email),
                    new KeyValuePair<string, string>("password", RegisterData.Password),
                });

                client.BaseAddress = new Uri("http://localhost:57975/");//54311
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add
                        (new MediaTypeWithQualityHeaderValue("application/json"));

                var response = client.PostAsync("/token", formContent).Result;
                if (response.IsSuccessStatusCode)
                {
                    var GetString = await response.Content.ReadAsStringAsync();
                    var StringResponce = Newtonsoft.Json.JsonConvert.DeserializeObject<MyToken>(GetString);
                    if (StringResponce != null)
                    {
                        MessageBox().Show(StringResponce.access_token);
                    }
                }
            }
        }

The added reference to System.Collections.Generic has the definition for KeyValuePair and like before, we wrap all asynchronous calls in using statements, then setup RegisterData the same as in PostRegister. Setting up FormUrlEncodedContent in this way is the only successful way I've been able to retrieve an access token. If you have been following along up to this point, the rest of this method should be self explanatory.

Change the constructor of MainWindow as follows:

C#
public MainWindow()
        {
            InitializeComponent();
            //GetRunAsync().Wait();
            //PostRegisterAsync().Wait();
            PostLogin().Wait();
        }

Start the server, then run the client and we should get something like below:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMany images are missing Pin
Tridip Bhattacharjee3-Jan-16 21:44
professionalTridip Bhattacharjee3-Jan-16 21:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.