Category: recordVisitors

RecordVisitors–packages and thanks–part 12

Now it is time to see the outdated packages and say thanks to the people that help me created all this project.

For this I install https://github.com/KrystianKolad/DotnetThx . The result is https://github.com/ignatandrei/RecordVisitors/blob/main/src/RecordVisitors/thanks.md

Also, I have installed dotnet outdated tool ( new version!) to see what I should improve

Also , I have installed dotnet-project-licenses to let the user see the license for the project . You can see all the licences at https://github.com/ignatandrei/RecordVisitors/blob/main/src/RecordVisitors/licenses.txt 

Also, a tool that worth is  dotnet-depends – make a try ( allow to run several seconds). You will be impressed by Norton Commander interface…

The CI in github yml it is

– name: helper – see Outdated, thanks , licences and depends

run: |

    cd src/RecordVisitors/       

    dotnet dotnet-outdated

    dotnet dotnet-thx

    dotnet dotnet-project-licenses -i .\RecordVisitors.sln

    # dotnet dotnet-depends

RecordVisitors–Static Analysis with SonarCloud–part 11

Now I should see if the code that I have written is enough good. One way to determine is static analysis – and sonarclould.io is open for open source.

It was pretty simple to setup

1.  I have install the tool  dotnet-sonarscanner

2. Add the secrets from sonnarcloud to Github

3. Add JAVA to the CI Github Action

    – name: Set up JDK 11

uses: actions/setup-java@v1

with:

java-version: 1.11

4. run the build with

cd src/RecordVisitors

dotnet dotnet-sonarscanner begin /k:”ignatandrei_RecordVisitors” /o:”ignatandrei-github” /d:sonar.login=”${{ secrets.SONAR_TOKEN }}” /d:sonar.host.url=”https://sonarcloud.io”

dotnet build

dotnet dotnet-sonarscanner end /d:sonar.login=”${{ secrets.SONAR_TOKEN }}”

And now I have quality gate A –  see https://sonarcloud.io/dashboard?id=ignatandrei_RecordVisitors

RecordVisitors- Readme for Nuget–part 10

Nuget now allow for a package to see a Markdown document. I choose to embed the readme.md file

I just embed into csproj file:

<ItemGroup>
     <None Include=”../../../readme.md” Pack=”true” PackagePath=”\” />
   </ItemGroup>

<PropertyGroup>

<PackageReadmeFile>readme.md</PackageReadmeFile>

</PropertyGroup>

I needed also to make a small modif , to remove HTML comments that were seeing into nuget

$path = “../../README.md”

$path =Resolve-Path $path

Write-Host $path

$fileContent = gc $path

Write-Host $fileContent.Length

For($i=0;$i -lt $fileContent.Length ; $i++){

$line = $fileContent[$i];

If ($line -match ‘^<!–‘) {

$state=’comment’

$fileContent[$i] =$null # because `continue` doesn’t work in a foreach-object

      }

If ($line -match ‘–>$’) {

$state=’content’

$fileContent[$i] =$null

      }

If ($state -eq ‘comment’) {

$fileContent[$i] =$null

      }

}

$fileContent |Set-Content $path

You can see the end result at https://www.nuget.org/packages/recordvisitors#

RecordVisitors- BDD–part 9

It is recommended to have tests. And better is to  see the output of the tests in some readable format .

On other hand, I do not like full BDD   frameworks as SpecFlow – I think that are too overkill in order to achieve less.

So – something like https://github.com/LightBDD/LightBDD seems to fit the bill.

After you read the documentation, it is not so difficult. You transform test from

[Fact]
public async void TestFakeUser()
{

    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetStringAsync("/recordVisitors/AllVisitors5Min");

    // Assert
    var str = "JeanIrvine";
    Assert.True(response.Contains(str), $"{response} must contain {str}");

}


into

HttpClient client;
string response;
private void Given_The_Application_Starts()
{
  StepExecution.Current.Comment("!!!Start application!!!!");
  client = _factory.CreateClient();
}

private async Task When_The_User_Access_The_Url(string url)
{
    response = await client.GetStringAsync(url);
}
private void Then_The_Response_Should_Contain(string str)
{            
    Assert.True(response.Contains(str), $"{response} must contain {str}");
}

[Scenario]
[ScenarioCategory("VisitorRecord")]
public async void TestFakeUser()
{
    await Runner
        .AddSteps(Given_The_Application_Starts)
        .AddAsyncSteps(
            _ => When_The_User_Access_The_Url("/recordVisitors/AllVisitors5Min")
        )
        .AddSteps(
            _ => Then_The_Response_Should_Contain("JeanIrvine")

        )
        .RunAsync();
                
}


Yes, it seems some more code – but you can re-use the functions and , more, the documentation looks great!

The results can bee seen at https://record-visitors.readthedocs.io/en/latest/BDD/LightBDDReport/

RecordVisitors–history of urls–part 8

Extending scope :why not record also the history  ? So – again, let the programmer choose what he wants to store https://record-visitors.readthedocs.io/en/latest/RecordVisitors/IRecordVisitorFunctions/methods/GetUrl/  and where to store : https://record-visitors.readthedocs.io/en/latest/RecordVisitors/IUsersRepository/methods/SaveHistory/ .

Created also 2 new endpoints :

/recordVisitors/GetUserId/{userName}

/recordVisitors/UserHistory/{userId}/{dateFrom:datetime:regex(\d{{4}}-\d{{2}}-\d{{2}})}/{dateTo?}

Make a default implementation of having the URL – does not start with api/ , does not contain api .

Make also documentation

Upload the package on Nuget : https://www.nuget.org/packages/RecordVisitors 

It appears simple, but there were 3 hours to implement all

Record visitors- work on issues–part 7

Now it is time to solve some issues  There were 12 issues written by me – you can see here:

https://github.com/ignatandrei/RecordVisitors/issues?q=is%3Aissue+is%3Aclosed

Between the most important:

  1. Improve readme.md with more links and explanations for potential programmer and contributors
  2. Write version in static constructor – to know about the version, if some issue occurs
  3. Added custom link  lastvisitors/minutes/{time:int} to see the latest visitors in a time frame
  4. Add read the docs site https://record-visitors.readthedocs.io/en/latest/
  5. Modification on the interfaces – replacing FUNC property with a real Func

There seems little – but it takes a while.

The links for the project are now

RecordVisitors – xml docs – part 6

Now it is time to write technical documentation  – XML comments to the rescue – first, read the https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/ .

Second, in order to minimize work, make the classes private / internal . See what I REALLY need to use the project – it remains some interfaces and extension methods.

It was helpful

  1. putting warning as errors at csproj level
  2. dotnet watch – to re-test the project each time some changes at the files occur :

dotnet watch test –project AutomatedTestRecord

Also, I have used https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute?view=net-5.0 

[assembly: InternalsVisibleTo(“AutomatedTestRecord”)]

in order that the test project works .

Next , I wanted something simple to generate the documents . I know about Sandcastle – https://github.com/EWSoftware/SHFB , however , it was too much for me. I opted for https://github.com/ap0llo/mddocs

You can see the final result here : https://ignatandrei.github.io/RecordVisitors/RecordVisitors/

RecordVisitors- NuGet–part 5

Now it the moment to deploy to NuGet. First , we should have automatic build and deploy to NuGet with GitHub Actions.  This is pretty simple –  the yml becomes

    – name: Pack

run: |

        cd src/RecordVisitors/

        # dotnet pwsh setVersion.ps1

        cd RecordVisitors

        dotnet pack -o nugetPackages

    – name: ‘Upload Artifact’

uses: actions/upload-artifact@v2

with:

name: RecordVisitorsNuget_${{github.run_number}}

path: src/RecordVisitors/RecordVisitors/nugetPackages

retention-days: 1

The modifications of the csproj project are the following

<ItemGroup>
     <PackageReference Include=”Microsoft.SourceLink.GitHub” Version=”1.0.0″ PrivateAssets=”All” />
     <None Include=”../../../readme.md” Pack=”true” PackagePath=”\” />
     <None Include=”../../../docs/rv.png” Pack=”true” PackagePath=”\” />
   </ItemGroup>

   <PropertyGroup>
     <Version>2021.5.29.1730</Version>
     <Authors>Andrei Ignat</Authors>
     <Description>This package help you record your visitors</Description>
     <Title>Record Visitors</Title>
     <PackageTags>C#;.NET;ASP.NET Core</PackageTags>
     <PackageReadmeFile>readme.md</PackageReadmeFile>
     <!–<PackageIconUrl>https://github.com/ignatandrei/RecordVisitors/raw/main/docs/rv.png</PackageIconUrl>–>
     <PackageIcon>rv.png</PackageIcon>
     <RepositoryUrl>https://github.com/ignatandrei/RecordVisitors</RepositoryUrl>
     <PackageProjectUrl>https://github.com/ignatandrei/RecordVisitors</PackageProjectUrl>
     <RepositoryType>GIT</RepositoryType>
     <Copyright>MIT</Copyright>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <IncludeSymbols>true</IncludeSymbols>
     <PublishRepositoryUrl>true</PublishRepositoryUrl>
     <EmbedUntrackedSources>true</EmbedUntrackedSources>
     <Deterministic>true</Deterministic>
     <DebugType>embedded</DebugType>

  </PropertyGroup>
   <PropertyGroup Condition=”‘$(GITHUB_ACTIONS)’ == ‘true'”>
     <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
   </PropertyGroup>

If you want more, read https://alex-klaus.com/better-nuget/  and https://docs.microsoft.com/en-us/nuget/create-packages/package-authoring-best-practices

RecordVisitors–CI –part 4

It will be perfect for any project to have a CI to improve feedback. GitHub actions is helpful here  – just put a gitlab.yml.

After few iterations, mine looks like this

name: BuildAndTest

on:

push:

branches: [ main ]

  pull_request:

    branches: [ main ]

jobs:

  build:

    #runs-on: ubuntu-latest

    runs-on: windows-2019

    steps:

    – uses: actions/checkout@v2

    – name: Setup .NET

      uses: actions/setup-dotnet@v1

      with:

        dotnet-version: 5.0.x

    – name: Restore dependencies

      run: |

        cd src/RecordVisitors

        dotnet restore

    – name: Build

      run: |

        cd src/RecordVisitors

        dotnet build –no-restore

    – name: Test

      run: |

        cd src/RecordVisitors

        dotnet test –no-build –verbosity normal

    – name: code coverage

      run: |

        cd src/RecordVisitors

        dotnet tool restore

        dotnet coverlet AutomatedTestRecord\bin\Debug\net5.0\AutomatedTestRecord.dll –target “dotnet” –targetargs “test RecordVisitors.sln –no-build”  –format opencover –exclude “[SampleWeb*]*”  –exclude “[xunit*]*” –verbosity detailed

        #dotnet coverlet AutomatedTestRecord\bin\Debug\net5.0\AutomatedTestRecord.dll –target “dotnet” –targetargs “test RecordVisitors.sln”  –format opencover  –verbosity detailed

        dotnet reportgenerator “-reports:coverage.opencover.xml” “-targetdir:coveragereport” “-reporttypes:HTMLInline;HTMLSummary;Badges”

    – name: ‘Upload Artifact’

      uses: actions/upload-artifact@v2

      with:

        name: codeCoverage

        path: src/RecordVisitors/coveragereport

        retention-days: 1

    – name: verify code coverage

      run: |

        ls src/RecordVisitors/coverage.opencover.xml

    – uses: codecov/codecov-action@v1

      with:

        files: src/RecordVisitors/coverage.opencover.xml

        fail_ci_if_error: true # optional (default = false)

        #verbose: true # optional (default = false)

    – name: Pack

      run: |

        cd src/RecordVisitors/RecordVisitors

        dotnet pack –include-source –include-symbols

Looks pretty much self-explanatory to me. Build, test, run code coverage and uploads to https://app.codecov.io/gh/ignatandrei/RecordVisitors  ( I am proud : CC 94 % )

RecordVisitors–code coverage–part 3

Now I have to do some code coverage . The easy way is to test the web application – doing an integration test. Use this as a starting point: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-5.0

I have 2 kind of tests: HappyPath  -when all is working ok – and  TestErrors  – when it is not.

The code for all working ok is

public async void TestFakeUser()
{
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetStringAsync("/recordVisitors/AllVisitors5Min");

    // Assert
    var str = "Jean Irvine";
    Assert.True(response.Contains(str),$"{response} must contain {str}");
                
}

and for testing errors

[Fact]
public  void TestFakeUser()
{
    _factory.RemoveServices = true;
    _factory.RemoveFakeUser = false;
    var ex = Record.Exception(()=>_factory.CreateClient());

    Assert.IsType<ArgumentException>(ex);
            
}
[Fact]
public async void TestNoUser()
{
    _factory.RemoveServices = false;

    _factory.RemoveFakeUser= true;
    // Arrange
    var client = _factory.CreateClient();

    // Act
    var response = await client.GetStringAsync("/recordVisitors/AllVisitors5Min");

    // Assert
    var str = "Jean Irvine";
    Assert.True(response.Contains(str), $"{response} must contain {str}");

}

 

The code coverage has reached 94% after 3 iterations – it is ok. You can see the results at https://app.codecov.io/gh/ignatandrei/RecordVisitors

 

Please make sure that you read also https://andrewlock.net/converting-integration-tests-to-net-core-3/

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.