Removing HTML tags from a string

Problem:

Screenshot_1493145278.png

The HTML from the API is in the exercise description. It looks like shit and is a potential security threat!

There a couple of ways you can tackle this particular beast:

  • Use REGEX:
    
    using System.Text.RegularExpressions;
    ...
    const string HTML_TAG_PATTERN = "<.*>";
    
    static string StripHTML (string inputString)
    {
     return Regex.Replace
     (inputString, HTML_TAG_PATTERN, string.Empty);
    }
    

    Created by a StackOverflow use capdragon

  • HTML Agility Pack
     public static string StripTagsCharArray(string source)
     {
     HtmlDocument htmlDoc = new HtmlDocument();
     htmlDoc.LoadHtml(source);
     htmlDoc.DocumentNode.SelectNodes("//comment()")?.ForEach(c=> c.Remove());
     return htmlDoc.DocumentNode.InnerText;
     }
    

    Created by users Ssilas777 and Thierry_S

  • And lastly the simplest but fastest one:
     public static string StripTagsCharArray(string source)
     {
     char[] array = new char[source.Length];
     int arrayIndex = 0;
     bool inside = false;
     for (int i = 0; i &amp;lt; source.Length; i++)
     {
     char let = source[i];
     if (let == '<')
     {
     inside = true;
     continue;
     }
     if (let == '>')
     {
     inside = false;
     continue;
     }
     if (!inside)
     {
     array[arrayIndex] = let;
     arrayIndex++;
     }
     }
     return new string(array, 0, arrayIndex);
     }
    

    Shared by AuthorProxy in the same thread a capdragons solution.

I went for what is behind door no. 3. IT suites my needs does not require any additional libraries to be loaded does not process the HTML code, so any malicious code it will get its ass ignored by being treated as a string.

Screenshot_1493146922.png

Voila!

Advertisements

Builder Pattern – Creating a full set of exercise objects

Three things need to happen in order for me to have a full ModelExercise from the API:

  1. Muscle Groups need to be downloaded
  2. Exercises need to be downloaded
  3. An association table must be built between the two.

Normally I’d use Entity Framework for this sort of thing but with PCL at a time when I started the project, it had quite a lot of problems and SQLite.NET-PCL  was the recommended solution.
That is okay but it means I need to build everything myself so long:


public virtual List<Exercise> Exercises {get; set;}

I need to build this relationship myself, so first of a model class:


 public class MuscleExerciseAssosiation
 {
 public int MuscleId { get; set; }
 public int ModelExerciseId { get; set; }
 public string MuslceType { get; set; }
 }

How I get muscles and exercises you can see in my previous post the association is build:


public override List<MuscleExerciseAssosiation> AssosiationGet()
{
if (_wgerExercises.Count == 0 || _muscles.Count == 0)
{
return new List<MuscleExerciseAssosiation>();
}
foreach (var exercise in _wgerExercises)
{
foreach (var muscle in exercise.muscles)
{
_muscleAssosiations.Add(
new MuscleExerciseAssosiation
{
ModelExerciseId = exercise.id,
MuscleId = muscle,
MuslceType = "Primary"
}
);
}
foreach (var muscle in exercise.muscles_secondary)
{
_muscleAssosiations.Add(
new MuscleExerciseAssosiation
{
ModelExerciseId = exercise.id,
MuscleId = muscle,
MuslceType = "Secondary"
}
);
}
}
return _muscleAssosiations;
}

which I then simply load into the database:


private async Task FillMuscleExerciseAssosiations(AbstractSourceFactory factory)
{
List<MuscleExerciseAssosiation> assosiations = factory.AssosiationGet();
await _connection.InsertAllAsync(assosiations);
}

But it is private… so I cannot call it outside of the class… Thats where the builder pattern comes in, as mentioned at the top of the post all 3 things need to happen in a sequence and they all need to happen, hence a new public method:


public async Task BuildMuscleDatabase(AbstractSourceFactory factory)
{
await FillMusclesFromDataStore(factory);
await FillExercisesFromDataStore(factory);
await FillMuscleExerciseAssosiations(factory);
}

calling all 3 in a sequence with one call from the outside, we are always sure that we called are methods correctly, and with this method being part of the IWorkoutStore interface we opened another ease of work for the future.

Refactoring for the glory of Bob!

Bob  has shown us the way and we shall not stray!!!

So in my previous API example, I used Newtonsofts JsonConvert.DeserializeObject(content);


JsonConvert.DeserializeObject<Type>(content);

The problem was that I have more than one API node I wish to pull on meaning that I had to either use anonymous types which would make the code hard to read or create a separate object for both responses:


private class _exerciseResponse
{
public int count { get; set; }
public string next { get; set; }
public string previous { get; set; }
public List<_wgerExercise> results { get; set; }
}
private class _muscleResponse
{
public int count { get; set; }
public string next { get; set; }
public string previous { get; set; }
public List<_wgerMuscle> results { get; set; }
}

It’s kind of sloppy because the response only differs when it comes to the “results” variable, so I decided to after checking that the core of the app works to do a bit of refactoring:


private class reposnse<T>
{
public int count { get; set; }
public string next { get; set; }
public string previous { get; set; }
public List<T> results { get; set; }
}

Logically after I call the JSON deserialize I call it giving it a proper type:


var response = JsonConvert.DeserializeObject<reposnse<_wgerExercise>>(content);

var response = JsonConvert.DeserializeObject<reposnse<_wgerMuscle>>(content);

Good now that leaves this lump of old code:


ExercisesGet()
{
string next;
next = await ParseJSON();
while (next != null)
{
await ParseJSON(next);
}
return _exercises;
}
private async Task<string> ParseJSON(string url= null)
{
if (url == null)
{
url = _URL;
}
var content = await _client.GetStringAsync(_URL);
var response = JsonConvert.DeserializeObject<_response>(content);
var exercises = response.results;
foreach (var exercise in exercises)
{
_exercises.Add(
new ModelExercise
{
Id = exercise.id,
Name = exercise.name,
Description = exercise.description,
}
);
}
return response.next;

}

It’s refactoring time!

First of all lets make the Method ParseJSON() generic:


private async Task<List<T>> ParseJSON<T>(string url = null)
{
_next = null;
if (url == null)
{
url = _ExerciseURL;
}
var content = await _client.GetStringAsync(url);
var response = JsonConvert.DeserializeObject<_response<T>>(content);
var results = response.results;
_next = response.next;

return results;
}

But now instead of returning our final object it retuns a list of our dummy objects so we need to make changes in the ExercisesGet() 


public async override Task<List<ModelExercise>> ExercisesGet()
{

var exercises = await ParseJSON<_wgerExercise>();

while (_next != null)
{
exercises.AddRange(await ParseJSON<_wgerExercise>(_next));
}

foreach (var exercise in exercises)
{
_exercises.Add(
new ModelExercise
{
Id = exercise.id,
Name = exercise.name,
Description = exercise.description,
UserGenerated = false
}
);
}

return _exercises;
}

and to have show of it being worth it ExercisesGet()’s sister MuscleGet()


public async override Task<List<Muscle>> MuscleGet()
{
var content = await _client.GetStringAsync(_MuscleURL);
var muscles = await ParseJSON<_wgerMuscle>();
while (_next!=null)
{
muscles.AddRange(await ParseJSON<_wgerMuscle>(_next));
}
foreach (var muscle in muscles)
{
_muscles.Add(
new Muscle
{
Id = muscle.id,
Name = muscle.name
});
}
return _muscles;
}

The only block that I do not like still where I repeat myself is:


while (_next!=null)
{
muscles.AddRange(await ParseJSON<_wgerMuscle>(_next));
}

And I will figure out how to re-factor this just not now ;).

It works?

Now as software developers we know that if something runs on the first try it either just did something terrible in the back-end that we are not seeing or It didn’t do anything at all…

And I am not going to lie it took me 1h to build the view model, add methods to the store, and then 45 mins to find out that I did not created a setter and getter for my main collection…

BAD!!


public ObservableCollection<ModelExercise> ModelExercises  = new ObservableCollection<ModelExercise>();

GOOD!


public ObservableCollection<ModelExercise> ModelExercises { get; private set; } = new ObservableCollection<ModelExercise>();

It’s stupid shit like that that makes you question your life as a coder ><.

Screenshot_1492431680

To do now:

  1. Remove that ugly ass html from the API 😦
  2. Change the buttons so that the drag down refreshes the dataset
  3. Build the Creator based on this
  4. Add muscle groups and sort/divide the list by them
  5. Add ability to edit/create new ones
  6. (optional) add images from the API

Super duper proud of myself 🙂

Abstract Factory fun

In this post, I wondered how I should encapsulate the JSON filling in of my Model Exercise Database.

The solution I have come up with is as follows:

  1. I created a new abstract class: AbstractSourceFactory.cs
     public abstract class AbstractSourceFactory
     {
     public abstract Task&amp;lt;List&amp;lt;ModelExercise&amp;gt;&amp;gt; ExercisesGet(string url = null);
     }
    
  2. Simple enough one method that returns a list of model Exercises an abstract class is nothing without it’s implementation:
    
    public class wgerSourceFactory : AbstractSourceFactory
     {
    
    private string _URL = "https://wger.de/api/v2/exercise/?format=api&amp;language=2";
     private List&lt;ModelExercise&gt; _exercises = new List&lt;ModelExercise&gt;();
     private HttpClient _client = new HttpClient();
     public async override Task&lt;List&lt;ModelExercise&gt;&gt;;&lt;/pre&gt;
    
    ExercisesGet()
     {
     string next;
     next = await ParseJSON();
     while (next != null)
     {
     await ParseJSON(next);
     }
     return _exercises;
     }
     private async Task&lt;string&gt; ParseJSON(string url= null)
     {
     if (url == null)
     {
     url = _URL;
     }
     var content = await _client.GetStringAsync(_URL);
     var response = JsonConvert.DeserializeObject&lt;_response&gt;(content);
     var exercises = response.results;
     foreach (var exercise in exercises)
     {
     _exercises.Add(
     new ModelExercise
     {
     Id = exercise.id,
     Name = exercise.name,
     Description = exercise.description,
     }
     );
     }
     return response.next;
    
    }
    
  3. I dont all the information that the API delivers so I made a small private class:
    private class _wgerExercise
     {
     public int id { get; set; }
     public string license_author { get; set; }
     public int status { get; set; }
     public string description { get; set; }
     public string name { get; set; }
     public string name_original { get; set; }
     public string creation_date { get; set; }
     public string uuid { get; set; }
     public int license { get; set; }
     public int category { get; set; }
     public int language { get; set; }
     public List&lt;int&gt; muscles { get; set; }
     public List&lt;int&gt; muscles_secondary { get; set; }
     public List&lt;int&gt; equipment { get; set; }
     }
    
    private class _response
     {
     public int count { get; set; }
     public string next { get; set; }
     public string previous { get; set; }
     public List<_wgerExercise> results { get; set; }
     }
    
    

    To store the JSON results

  4. And now in my DataStore Class I have a method:
    
    public async Task FillExercisesFromDataStore(AbstractSourceFactory factory)
    {
    List<ModelExercise> exercises = await factory.ExercisesGet();
    foreach (var exercise in exercises)
    {
    await _connection.InsertAllAsync(exercises);
    }
    }
    
  5. Now in the future, I can pass any factory I want and I can still get all the data in 🙂 super proud of myself for not coding like a chump 😉

Tomorrow I’ll build a page to display it all and it will come down crashing on my head with all the mistakes I made, but whatever! Today was a good day!

Fitness Buddy – App analysis to find the best UI

Fitness Buddy popped up on my app store as a promotion for 0,5 zł (10 cents? +/-), why the hell not lets take a look 🙂

1

Nice exercise details, not going to do it because it would take quite a significant amount of time to collect this info and this project is not about data collection but coding.

2.png

This is just the way I want mine to be only I want to use the list view a little bit better and add a description of the workout below the name. Right now it does not give too much information at a first glance…

3

Workout details, perfect, a great thing I may put in late is the separation of workout parts I like it. Right now it’s a bit too much of a change for a part I am done with (well 1-3 hours of coding, but I just feel I can spend it better).

4

So far I was very positive but this is kind of meh to me:

  • You can’t put in individual weight for a rep, not everyone does 5×5…
  • It’s not very attractive is it now?
  • On a very much + side it is super intuitive!

5

Notes… Notes everywhere, it’s not facebook yo! This I like but because it gave me an idea on how to show progress in my app, so the weight will be on Y axis and a number of reps will be color coded (>50% of set reps RED, <=50%>75% AMBER, <=75%>=100% GREEN, >100% BLUE) Easy to read and gives a cool indication of whether you are not putting up too much weight :).

It’s again an OK app really, gave me some really good ideas!

Should you ever stop encapsulating?

So in my app I have a fairly simple database interface:


public interface IWorkoutStore
{

Task<IEnumerable<Workout>> GetWorkoutsAsync();
Task<Workout> GetWorkout(int id);
Task<WorkOutType> GetWorkoutType(int typeId);
Task<IEnumerable<Exercise>> GetRelatedExercises(int workoutId);
Task AddWorkout(Workout workout);
Task UpdateWorkout(Workout workout);
Task DeleteWorkout(Workout workout);

}

And of course, it’s implementation. Now what I wanted to do is Add an automatic Exercise fill in using API I found here since it will be mostly static I wanted to have it load up the data once and keep it in the database, later on, the user might want to refresh the dataset so that option also should be available. Now what I am wondering about is this:
I may have a different store in the future, so I want to encapsulate the process of loading so that changing the data source is easy. The BIG question is: Is it ok to encapsulate something within an encapsulation? How far can the rabbit hole go until a measure you put in to avoid spaghetti code turn into its own brand of spaghetti.

My current Idea is to have a Abstract Factory that gives different methods towards different data sources, but I still wonder is it the right choice? I mean I am an experienced enough coder that I know that writing something perfectly is impossible