Click here to Skip to main content
15,888,182 members
Home / Discussions / C#
   

C#

 
AnswerRe: C# Change Directory Function Pin
BillWoodruff13-Sep-15 22:07
professionalBillWoodruff13-Sep-15 22:07 
QuestionUnable to work with Multi-Threading Pin
Bastar Media12-Sep-15 4:02
Bastar Media12-Sep-15 4:02 
AnswerRe: Unable to work with Multi-Threading Pin
OriginalGriff12-Sep-15 4:55
mveOriginalGriff12-Sep-15 4:55 
GeneralRe: Unable to work with Multi-Threading Pin
Bastar Media12-Sep-15 20:27
Bastar Media12-Sep-15 20:27 
GeneralRe: Unable to work with Multi-Threading Pin
OriginalGriff12-Sep-15 20:59
mveOriginalGriff12-Sep-15 20:59 
SuggestionRe: Unable to work with Multi-Threading Pin
Richard MacCutchan12-Sep-15 5:42
mveRichard MacCutchan12-Sep-15 5:42 
AnswerRe: Unable to work with Multi-Threading Pin
Pete O'Hanlon12-Sep-15 11:42
mvePete O'Hanlon12-Sep-15 11:42 
QuestionSimple and reusable system for user registration and tracking and auto-updates Pin
Bartosz Jarmuż12-Sep-15 1:02
Bartosz Jarmuż12-Sep-15 1:02 
Hello,
I would like to ask for a 'code review' of the project below, as I have never designed such a thing before and I wonder if there are any serious problems with the code/approach below.

Here's a little background - I create a bunch of small and mostly internal WPF applications for my company - usually for some file manipulation etc. For these programs, I would like to start collecting user info - who uses them, how often, most importantly - which version is used.

It's partly for my personal skill development, but I also want to introduce auto-updating for my apps - some of them have this feature already, but they rely on text files located on shared drive so obviously not a good solution.

The intended audience is not a large crowd, probably fewer than 50 users. The calls to the database will most likely happen only on the application launch.

The idea is that I have a generic 'helper' dll, which I reference in my projects so that in each of the programs I call a simple method and have the repetitive registration handling out of my mind. All the data is stored in a single Azure database called MyDB, and all the programs should connect through the same API (also hosted in Azure), called e.g. MyApi (myapi.azuresites.net).

So, looking from the point of view of a single client app:
C#
public MainWindow()
       {
           InitializeComponent();
           Register = new RegistrationHelper();
           var progressInfo = new Progress<string>(p => StatusInfo = p);
           Register.HandleRegistration(progressInfo);
           //and that's it
   }
Now, the helper library contains a smart constructor that will deduct all the info I need for my database (email is optional only for some programs with explicit registration):
C#
private const string DefaultApiAddress = "<a href="https://MyApi.azuresites.net">https://MyApi.azuresites.net</a>";
public RegistrationHelper(string email = null)
{
    ApiUri = new Uri(DefaultApiAddress);
    UserName = Environment.UserName;
    MachineName = Environment.MachineName;
    //email is not needed for registration
    UserProvidedEmail = email;
    CurrentAssembly = Assembly.GetEntryAssembly();
    ProgramName = CurrentAssembly.GetName().Name;
    ProgramVersion = FileVersionInfo.GetVersionInfo(CurrentAssembly.Location).FileVersion;
}
Then it has a public method for running handling the registration (which obviously should not block program execution):
C#
public void HandleRegistration(IProgress<string> progressInfo)
{
    Task.Run((() => HandleRegistrationAsync(progressInfo)));
}
Which calls a private handler:
C#
private async Task HandleRegistrationAsync(IProgress<string> progressInfo)
{
    try
    {
        progressInfo.Report("Connecting...");
        RegisteredUserId = await GetUserIdAsync();
        if (RegisteredUserId == 0)
        {
            RegisteredUserId = await RegisterUserByNameAsync();
            if (RegisteredUserId > 0)
            {
                progressInfo.Report(string.Format("Newly registered. Id: {0}", RegisteredUserId));
            }
            else
            {
                progressInfo.Report("Registration failed");
            }
        }
        else if (RegisteredUserId < 0)
        {
            progressInfo.Report(string.Format("Not registered. {0}", RegisteredUserId));
        }
        else
        {
            progressInfo.Report(string.Format("Updating user {0} info...", RegisteredUserId));
            progressInfo.Report("Registered. Id: " + RegisteredUserId);
        }
    }
    catch (Exception ex)
    {
        progressInfo.Report("Connection error");
        if (ThrowExceptions)
            throw ex;
    }
}
And the methods that call the API are all pretty similar, structured as follows:
C#
public async Task<int> UpdateProgramUsageAsync()
{
    try
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = ApiUri;
            client.DefaultRequestHeaders.Accept.Clear();
            HttpResponseMessage response = await client.GetAsync(string.Format("api/update/{0}/{1}/{2}/", RegisteredUserId, ProgramName, ProgramVersion));
            return response.IsSuccessStatusCode
                ? Convert.ToInt32(response.Content.ReadAsStringAsync().Result)
                : -1;
        }
    }
    catch (Exception)
    {
        if (ThrowExceptions)
            throw;
        else
            return -666;
    }
}
Now, what's in the web API:

There is a single UserController (apart from the stuff that comes out of the box from the WebApi template). It contains the connection string to the database (hardcoded), plus a bunch of constants for StoredProcedures names and stuff like that.

Then, my controller methods are structured as follows:
C#
private const string ConnectionString = "allthestuffsensitivetoconnecttodatabase";
[Route("api/getid/{username}")]
public async Task<int> GetIdAsync(string username)
{
    using (var conn = new SqlConnection(ConnectionString))
    {
        conn.Open();
        if (conn.State == ConnectionState.Open)
        {
            var result = await ExecuteScalarCommandAsync(GetRegisteredUserByName, conn,
                new[]
                    {
                        new SqlParameter(UserNameCol, username), 
                    });
            if (result != null && !(result is DBNull))
            {
                return Convert.ToInt32(result);
            }
            return 0;
        }
    }
    return -1;
}

private async Task<object> ExecuteScalarCommandAsync(string commandName, SqlConnection conn, SqlParameter[] parameters)
{
    using (var command = new SqlCommand(commandName, conn)
    {
        CommandType = CommandType.StoredProcedure,
    })
    {
        command.Parameters.AddRange(parameters);
        return await command.ExecuteScalarAsync();
    }
}
Also, as for the methods that not only 'get' values, but also update database, I am using the GET as well.

The one below is a match of UpdateProgramUsageAsync() pasted above:
C#
[Route("api/update/{userid}/{programname}/{version}")]
[AcceptVerbs("GET")]
public async Task<int> UpdateProgramUsageAsync(string userid, string programname, string version)
{
    using (var conn = new SqlConnection(ConnectionString))
    {
        conn.Open();
        if (conn.State == ConnectionState.Open)
        {
            var result = await ExecuteScalarCommandAsync(UpdateProgramUsage, conn,
        new[]
            {
                new SqlParameter(UserIdCol, userid), 
                new SqlParameter(ProgramNameCol, programname), 
                new SqlParameter(VersionCol, version)
            }
        );
            if (result != null && !(result is DBNull))
            {
                return Convert.ToInt32(result);
            }
        }
    }
    return 0;
}
As you can see, it relies on stored procedures updating the database and returning some response codes. The procedures are pretty simple (get value, put value into a table, nothing fancy).

modified 12-Sep-15 10:21am.

AnswerRe: Simple and reusable system for user registration and tracking and auto-updates Pin
OriginalGriff12-Sep-15 1:43
mveOriginalGriff12-Sep-15 1:43 
GeneralRe: Simple and reusable system for user registration and tracking and auto-updates Pin
Bartosz Jarmuż12-Sep-15 4:19
Bartosz Jarmuż12-Sep-15 4:19 
AnswerRe: Simple and reusable system for user registration and tracking and auto-updates Pin
Dave Kreskowiak12-Sep-15 3:25
mveDave Kreskowiak12-Sep-15 3:25 
GeneralRe: Simple and reusable system for user registration and tracking and auto-updates Pin
Bartosz Jarmuż12-Sep-15 4:22
Bartosz Jarmuż12-Sep-15 4:22 
QuestionC# RUN zero-based index of the longest run in a string Pin
Erics Johnson11-Sep-15 4:40
Erics Johnson11-Sep-15 4:40 
AnswerRe: C# RUN zero-based index of the longest run in a string Pin
Richard Andrew x6411-Sep-15 5:09
professionalRichard Andrew x6411-Sep-15 5:09 
GeneralRe: C# RUN zero-based index of the longest run in a string Pin
Erics Johnson12-Sep-15 10:56
Erics Johnson12-Sep-15 10:56 
QuestionAdvantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
Bartosz Jarmuż11-Sep-15 0:52
Bartosz Jarmuż11-Sep-15 0:52 
AnswerRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
OriginalGriff11-Sep-15 1:16
mveOriginalGriff11-Sep-15 1:16 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
Bartosz Jarmuż11-Sep-15 1:39
Bartosz Jarmuż11-Sep-15 1:39 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
OriginalGriff11-Sep-15 2:02
mveOriginalGriff11-Sep-15 2:02 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
Bartosz Jarmuż11-Sep-15 2:24
Bartosz Jarmuż11-Sep-15 2:24 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
OriginalGriff11-Sep-15 2:33
mveOriginalGriff11-Sep-15 2:33 
AnswerRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
F-ES Sitecore11-Sep-15 3:58
professionalF-ES Sitecore11-Sep-15 3:58 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
Bartosz Jarmuż11-Sep-15 4:40
Bartosz Jarmuż11-Sep-15 4:40 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
Bartosz Jarmuż11-Sep-15 7:15
Bartosz Jarmuż11-Sep-15 7:15 
GeneralRe: Advantages of using .dll files over linking .cs files to projects (for my own generic helper classes / extension methods) Pin
F-ES Sitecore12-Sep-15 2:19
professionalF-ES Sitecore12-Sep-15 2:19 

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.