Skip to main content

Posts

Showing posts from April, 2021

Architecture Weekly

Interested in software architecture? I discovered ‘Architecture Weekly’ , a weekly list of links so you know what to read during the weekend.

C#–Hide a base class for usage outside an assembly

I created an abstract base class in C# but didn’t want it to be used outside the assembly I created it in. How can you achieve this? Your first guess could be to change the access modifier of the base class to internal . When you try to do this you’ll get the following error message: Inconsistent accessibility: base class 'MyBaseClass' is less accessible than class 'MyInheritedClass' You have no other choice than to make the abstract class public what makes it visible outside the assembly. Is there still a way to only allow classes in the same assembly to implement it? The trick is to make the abstract base class public , but give it an internal default constructor: This will allow MyBaseClass to be visible outside the assembly, but classes outside the assembly cannot inherit from it.

Azure DevOps–Auditing streams

Yesterday I blogged about Azure DevOps audit logs .  Although you could export the logs, it was only limited to the last 90 days. To have a full audit log over time, we need to take a different approach through audit streams. Audit streams represent a pipeline that flows audit events from your Azure DevOps organization to a stream target. Every half hour or less, new audit events are bundled and streamed to your targets. Currently, the following stream targets are available for configuration: Splunk – Connect to on-premises or cloud-based Splunk. Azure Monitor Log - Send auditing logs to Azure Monitor Logs . Logs stored in Azure Monitor Logs can be queried and have alerts configured. Look for the table named AzureDevOpsAuditing. You can also connect Azure Sentinel to your workspace. Azure Event Grid – For scenarios where you want your auditing logs to be sent somewhere else, whether inside or outside of Azure, you can set up an Azure Event Grid connection. Cr

Azure DevOps–Auditing

A lesser known feature in Azure DevOps Services(it doesn’t exist in Azure DevOps) is the audit log. The audit log contains many changes that occur throughout an Azure DevOps organization. The feature is still in preview and the list of events that are tracked through this feature keeps growing. Check the audit logs Let’s find out how to check the audit log: Sign in to your organization ( https://dev.azure.com/{yourorganization } ). Select Organization settings in the bottom left corner. Select Auditing from the left menu . The auditing page gives you a limited view into the available audit events and recorded data. If you want to access all the data, it is possible to export the data.  Click on the Export log button in the right corner. Remark: If you can't find the auditing event you're looking for in the following table, be sure to check the REST API: https://auditservice.dev.azure.com/{YOUR_ORGANIZATION}/_apis/audit/actions . Rep

The Art of Computers

Scott Hanselman is always entertaining but if you are new to programming or not, this is a great talk about some important concepts in IT:

ASP.NET HttpHandler - Concurrent requests

To solve a specific issue(maybe more about this in another post) we created a custom HttpHandler in ASP.NET. Inside this handler we need access to the session. Therefore we implemented the IRequiresSessionState marker interface: The HttpHandler worked as expected until we started to increase the load. We noticed that a lot of requests remained pending… This could be traced to the usage of the IRequiresSessionState that put an exclusive lock on the current session. As a consequence the # of concurrent requests for one user are restriced. The good news is that another marker interface exists, IReadOnlySessionState , that does not acquire an exclusive lock. In case you only need to read data from the session state and don’t need to change any session data, you can switch to this interface:

Kubernetes–Schedule a pod on a Linux node–Part 2

Yesterday I blogged about the usage of the “kubernetes.io/os” nodeselector to schedule a pod specifically on a windows or linux node pool. Today I want to share another way through the usage of taints and tolerations. This Kubernetes feature allows users to mark a node (taint the node) so that no pods can be scheduled to it, unless a pod has a toleration that indicates it will accept this taint. Using this Kubernetes feature we can create nodes that are reserved (dedicated) for specific pods.  Using this, we can pick one OS and taint all the nodes with this OS, so that any pods that do not specify toleration will use the non-tainted nodes. This Taint effectively allows us to specify a default OS for the cluster, and if you want to use the other OS, you need to state this explicitly. To enable this, we first need to taint our Windows nodes. We would run this command for each Windows node: kubectl taint nodes <nodeName> OS=Windows:NoSchedule After this is applied it wil

Kubernetes–Schedule a pod on a Linux node–Part 1

On our Kubernetes(AKS) cluster we have multiple node pools some with Linux nodes and some with Windows nodes: But what if you want to schedule specific workloads on Linux or Windows nodes? The easiest way to control this is through the OS node selector. The OS node selector(“kubernetes.io/os”) is a built-in selector which indicates the OS that the node is running. We can use this selector to ensure that the pod is only deployed to nodes with the right OS. Here is an example for Windows pods: And here is in example for Linux pods: Unfortunately you don’t always have direct control on the pod specification(e.g. when you are using a 3th party Helm chart). In that case we have to take a different approach. But that is for another blog post tomorrow…

XUnit–Dependency Injection

To use the standard IoC container inside your Xunit tests, I would recommend to use a separate fixture. Inside this fixture you can add all dependencies to the ServiceCollection and build the ServiceProvider: Now you can use the IoC container inside your tests by injecting the fixture inside the constructor:

C# 9–Target typed conditional expressions

Before C# 9, I didn’t use conditional expressions much because the different branches in the conditional couldn’t have different types. With C# 9, this has finally changed; different types are allowed, as long as both of them convert to the target type. Let’s explain this through an example; I have a Pet baseclass and two inherited classes Cat and Dog. If I want to use them in a conditional expression in .NET Core 3.1(using C# 8), I get the following error message: CS8400: Feature ‘target typed conditional expressions’ is not available in C# 8.0. Please use language version 9.0 or greater. When I upgrade to .NET 5(using C# 9) the code above works! More information: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-conditional-expression

Intentional Design

There a thousands(millions?) of (mobile) apps out there. But what makes the difference between a good and a great app experience? The answer is simple: Intentional design . I recommend watching this session by Doug LeMoine . Doug walks us through 5 elements of intentional design. Each element needs to be considered in your design process: Radical Simplification Deep Understanding Extreme Focus Personal Connection Direct Communication

ASP.NET Core–Avoid AutoRedirect in named or typed httpclients

In ASP.NET Core I typically avoid to use the HttpClientFactory directly but instead I use the named or typed httpclients. You can configure the client using the AddHttpClient method(in case of named clients): or inside the constructur (in case of typed clients): This provides proper encapsulation and isolation of the configuration of each httpclient. But what if you want more control on the HttpClient behavior? For example, you want to disable AutoRedirect on the HttpClient. That is not possible through the configuration above. In that case you can use the ConfigurePrimaryHttpMessageHandler extension method. For a named client: For a typed client:

Angular --deploy-url and --base-href

As long you are running your Angular application at a root URL (e.g. www.myangularapp.com ) you don’t need to worry that much about either the ‘--deploy-url’ and ‘--base-href’ parameters. But once you want to serve your Angular application from a server sub folder(e.g. www.mywebsite.com/angularapp ) these parameters become important. --base-href If you deploy your Angular app to a subfolder, the ‘--base-href’ is important to generate the correct routes. This parameter will update the <base href> tag inside the index.html. For example, if the index.html is on the server at /angularapp/index.html , the base href should be set to <base href="/angularapp/"> . More information: https://angular.io/guide/deployment --deploy-url A second parameter that is important is ‘--deploy-url’. This parameter will update the generated url’s for our assets(scripts, css) inside the index.html. To make your assets available at /angularapp/, the deploy url should

Link an Azure Container Registry to multiple AKS clusters

To link an Azure Container Registry(ACR) to an AKS cluster, you can do this during cluster creation or set it up after the cluster is up and running. Create a new cluster with ACR : az aks create -n myAKSCluster -g myResourceGroup --generate-ssh-keys --attach-acr myContainerRegistry Link ACR after creation : az aks update -n myAKSCluster -g myResourceGroup --attach-acr myContainerRegistry This works as long as the ACR and the AKS cluster are inside the same subscription.  If you try the command above with the ACR and AKS in different subscriptions, you get the following error message: cli.azure.cli.core.azclierror: The resource with name 'myContainerRegistry' and type 'Microsoft.ContainerRegistry/registries' could not be found in subscription 'MySubscription'. cli.azure.cli.core.azclierror: The resource with name 'myContainerRegistry' and type 'Microsoft.ContainerRegistry/registries' could not be found in subscription 'M

Azure AKS- Scale out to ACI through virtual nodes

One of the nice features of AKS(Azure Kubernetes Service) is that you can create a virtual nodes that can be used to scale out to ACI. This feature is really useful in following scenario’s: Temporary burst of capacity On-demand processing, e.g. batch jobs Isolated processing for untrusted code The virtual nodes feature is build on top of the Virtual Kubelet technology. To enable this feature you need to extend the deployment yaml with the configuration below. This configuration will first try to schedule the pod on the default node pools. If not enough resources are available, the pod will be scheduled on the virtual node: A good introduction can be found here:   Remark: Virtual nodes only supports Linux pods at the moment of writing

Application Insights–Report browser usage

I was looking at a way to report browser usage statistics through Application Insights. Here are the required steps: Browse to the Application Insights resource in the Azure Portal Go to the Monitoring section and click on Logs Click on Get Started on the Welcome screen Close the queries screen Enter the following query and click on Run pageViews | summarize count() by client_Browser Check the results  

AutoRest- Duplicate operation detected

I was trying to use AutoRest to generate a client SDK for one of my API’s. This turned out not to be the success I was hoping for. Yesterday I explained that I got into trouble because an OperationId was missing. But after adding it, it still didn’t work. Instead I got the following error message: Duplicate operation detected Here was the API controller I was using: AutoRest uses the OpenAPI generated through Swashbuckle. When I took  a look at the OpenAPI file, I noticed that indeed the same OperationId was used: This is because I was using the ActionName as the OperationId. As I have multiple Action methods with the same name they all result in the same OperationIe To fix it, you can do 2 things: Using the [SwaggerOperation] attribute Using the Name property on the Http attribute ([HttpGet], [HttpPost],…) Using the [SwaggerOperation] attribute By adding a [SwaggerOperation] attribute to the controller action method, you can control the generated Opera

AutoRest–OperationId is required for all operations

I was trying to use AutoRest to generate a client SDK for one of my API’s. This turned out not to be the success I was hoping for. I downloaded the swagger.json file for my API and executed AutoRest through the following command: autorest --csharp --input-file=swagger.json This command failed with the following exception message: FATAL: OperationId is required for all operations. Here was the API controller I was using: And here is an extract of the generated swagger.json: As you can see, there is indeed no OperationId specified in the swagger.json. The swagger documentation has the following to tell about the OperationId: operationId is an optional unique string used to identify an operation. If provided, these IDs must be unique among all operations described in your API. Some common use cases for operationId are: Some code generators use this value to name the corresponding methods in code. Links can refer to

AutoRest–Generate a client library for your REST API

I was investigating some ways to generate a C# client library based on the OpenAPI definition of my REST API. One of the solutions I found was AutoRest . AutoRest is an open source tool created by Microsoft so that Azure service teams could start producing generated client libraries from new Swagger and OpenAPI 2.0 specifications. Install AutoRest To install AutoRest, you can use NPM: # Depending on your configuration you may need to be elevated or root to run this. (on OSX/Linux use 'sudo' ) npm install -g autorest # run using command 'autorest' to check if installation worked autorest – --help Generate a C# client To generate a C# client, you first need to have your OpenAPI file available. When you are using Swashbuckle in ASP.NET Core, you can browse to the swagger endpoint and download the swagger.json. Next step is to invoke AutoRest: autorest --input-file=swagger.json – --csharp This will generate a C# project with a REST AP