alias winrun='cmd.exe /c start cmd /k'
So now if I'm in Bash and want to run a dotnet project I just type:
winrun dotnet run
alias winrun='cmd.exe /c start cmd /k'
So now if I'm in Bash and want to run a dotnet project I just type:
winrun dotnet run
# Script to create a new Visual Studio project folder from an existing one
# Usage: ./csprojclone.sh Your.Namespaced.Source Your.Namespaced.Destinationn
if [ $# -lt 2 ]
then
echo "Please pass source and destination namespace arguments"
return -1
fi
source=${1%%/}
dest=${2%%/}
if [[ ! -d $source ]]
then
echo "Source directory does not exist or isn't a folder - make sure you are in the correct working directory"
return -1
fi
if [[ -e $dest ]]
then
echo "Destination folder already exists in the working directory"
return -1
fi
oldproject=${source%%.UnitTests}
oldproject=${oldproject##*.}
newproject=${dest%%.UnitTests}
newproject=${newproject##*.}
cp -r $source $dest
rm -r $dest/bin/
rm -r $dest/obj/
find $dest -iname "*$source*" -exec rename -v "s/$source/$dest/" {} \;
find $dest -iname "*$oldproject*" -exec rename -v "s/$oldproject/$newproject/" {} \;
find $dest -type f -print0 | xargs -0 sed -i "s/$source/$dest/g"
find $dest -type f -print0 | xargs -0 sed -i "s/$oldproject/$newproject/g"
As per the script, the usage is to call the script from within your solution directory, passing in the name of the existing project folder and then a destination one. The script will clone the source, rename the files, search and replace the namespace change and update any classes that had the specific project name in. If you're using it on a unit tests project, it will strip of ".UnitTests" from the path - so if that's not your naming convention then feel free to edit those bits.
Here's an example of how it might work:
PWD = /path/to/SolutionFolder
My.Namespace.UserRepository
My.Namespace.UserRepository/My.Namespace.UserRepository.csproj
My.Namespace.UserRepository/MongoStuff/...
My.Namespace.UserRepository/IUserRepositoryConfig.cs
etc..
. /path/to/script/csprojclone.sh My.Namespace.UserRepository My.Namespace.OrderRepository
Will create:
My.Namespace.OrderRepository
My.Namespace.OrderRepository/My.Namespace.OrderRepository.csproj
My.Namespace.OrderRepository/MongoStuff/...
My.Namespace.OrderRepository/IOrderRepositoryConfig.cs
With all namespaces also updated.
// SomeClass.cs
public class SomeClass
{
private readonly IDependency1 _dependency1;
private readonly IDependency2 _dependency2;
private readonly IDependency3 _dependency3;
public SomeClass(IDependency1 dependency1, IDependency2 dependency2, IDependency3 dependency3)
{
_dependency1 = dependency1 ?? throw new ArgumentNullException(nameof(dependency1));
_dependency2 = dependency2 ?? throw new ArgumentNullException(nameof(dependency2));
_dependency3 = dependency3 ?? throw new ArgumentNullException(nameof(dependency3));
}
}
// SomeClass.tests.cs
[TestFixture]
public class SomeClassTests
{
private Mock<IDependency1> _dependency1Mock;
private Mock<IDependency2> _dependency2Mock;
private Mock<IDependency3> _dependency3Mock;
[SetUp]
public void SetUp()
{
_dependency1Mock = new Mock<IDependency1>();
_dependency2Mock = new Mock<IDependency2>();
_dependency3Mock = new Mock<IDependency3>();
}
[TestCase("dependency1")]
[TestCase("dependency2")]
[TestCase("dependency3")]
public void Ctor_RequiredDependencyNull_ThrowsException(string dependency)
{
var setup = new Dictionary<string, Action>
{
{"dependency1", () => _dependency1Mock = null },
{"dependency2", () => _dependency2Mock = null },
{"dependency3", () => _dependency3Mock = null }
};
setup[dependency]();
Func<SomeClass> act = GetDefaultSut;
act.Should().Throw<ArgumentNullException>().And.ParamName.Should().Be(dependency);
}
private SomeClass GetDefaultSut()
{
return new SomeClass(_dependency1Mock?.Object, _dependency2Mock?.Object, _dependency3Mock?.Object);
}
}
My above example is for NUnit, using FluentAssertions and Moq but can be converted to your testing tools of choice.
An even easier option, when all your dependencies are required is to use the "GuardClauseAssertion" from "AutoFixture.Idioms"
private readonly Fixture _fixture;
public SomeClassTest(){
_fixture = new Fixture();
_fixture.Customize(new AutoMoqCustomization());
}
[Test]
public void Ctor_NullDependency_Throws()
{
new GuardClauseAssertion(_fixture)
.Verify(typeof(SomeClass).GetConstructors());
}
public class LoggingMessageHandler : DelegatingHandler
{
private readonly IExceptionLogger _exceptionLogger;
public LoggingMessageHandler(IExceptionLogger exceptionLogger)
{
_exceptionLogger = exceptionLogger ?? throw new ArgumentNullException(nameof(exceptionLogger));
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
var response = await base.SendAsync(request, cancellationToken);
if (!response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
await _exceptionLogger.LogExceptionAsync(new HttpRequestException(
$"Api call to {request.RequestUri} failed with status code {(int)response.StatusCode}. Response content: {responseContent}"));
}
return response;
}
}
Your implementation of "IExceptionLogger" may vary, but this is your opportunity to write something to your logs/DB etc.
To set this delegating handler on your HttpClient, setup the Microsoft DI container as follows:
services.AddHttpClient<ISomeClient, SomeClient>().AddHttpMessageHandler<LoggingMessageHandler>()
Since this class and custom logic will typically live in your composition root, I'd recommend passing the builder delegate down to any class libraries you are building (where you choose to define the ServiceCollectionExtensions inside the class library). For example:
Startup.cs:
services.AddMyCustomLibrary(builder => builder.AddHttpMessageHandler<LoggingMessageHandler>());
CustomLibrary/ServiceCollectionExtensions.cs:
public static void AddMyCustomLibrary(this IServiceCollection services, Action<IHttpClientBuilder> clientBuilderDelegate = null)
{
var someInnerClientBuilder = services.AddHttpClient<ISomeInnerClient, SomeInnerClient>();
clientBuilderDelegate?.Invoke(someInnerClientBuilder);
}