Der von Microsoft lange Zeit angekündigte Ahead-of-Time-Compiler "Native-AOT" lässt sich erstmalig in .NET 7 nutzen – zumindest in Konsolenprojekten.
Verschiedene Optionen für dotnet publish erlauben individuelle Anpassungen der ohne Dockerfile mit .NET CLI angelegten Docker-Deployments.
Whenever people encounter barriers, whether due to disability, age or situation, they are denied full participation in society and a self-determined life. The goal of digital accessibility is to enable all people to understand and interact with user interfaces without assistance. In this article, I would like to explain which areas of accessibility need to be considered in order to come a big step closer to the goal of a website that is understandable and usable for all people.
Ein neues NuGet-Paket kümmert sich um die passende Docker-Konfiguration für containerisierte .NET-Anwendungen.
Auf Grund der regelmäßigen Artikelaufrufe über die SOLID-Prinzipien hatte ich mich vor einiger Zeit dazu entschlossen, diese Serie auch in Form eines kleinen Buches anzubieten. Ab sofort kann dieses Buch (gedruckt, als auch als E-Book) in allen bekannten Buchhandlungen und digitalen Plattformen bestellt werden. Neben den SOLID-Prinzipien werden in dem Buch auch die Prinzipien KISS, DRY, LoD und YAGNI angesprochen.
Natürlich stehen die bisherigen Artikel auch weiterhin hier auf dem Blog kostenlos zur Verfügung. Somit kann jeder frei entscheiden, ob man die Artikel lieber online, auf dem E-Book Reader oder als gedrucktes Buch lesen möchte. Aktuell liegt das Buch nur in Deutsch vor. Ich gehe aber davon aus, dass ich in einiger Zeit auch die englische Variante anbieten kann.
Der Preis für das knapp 100 Seiten umfassende Buch liegt für die gedruckte Variante (ISBN-13: 9783734746857) bei 6,99 € und für das E-Book (ISBN-13: 9783757870706) bei 4,99 €.
Der Online-Infotag widmet sich diversen Themen rund um C#, .NET und KI-unterstützte Softwareentwicklung.
Wer WebAPI-Projekte mit ASP.NET Core erstellt, hat die Wahl zwischen dem in .NET 6.0 eingeführten Minimal-API-Stil und dem ursprünglichen API-Stil.
In today's fast-paced business world, staying ahead of the competition requires access to specialized expertise. However, hiring full-time experts can be costly and time-consuming, especially for small and medium-sized enterprises (SMEs) or startups. This is where the concept of "Expert as a Service" (EaaS) comes into play, providing businesses with on-demand access to industry-leading experts. In this article, we will explore the rise of EaaS, its benefits, and how it is shaping the future of on-demand expertise.
Microsoft hat in .NET 7.0 den Umgang mit Befehlsnamen und deren Parametern auf der Kommandozeilen vereinheitlicht.
Kürzlich erhielt ich eine Frage von einem Leser meines Buches Cross-Plattform-Apps entwickeln mit Xamarin.Forms, der auf Seite 336 des Buches auf meine Behandlung von SQLite-Datenbankverbindungen in Xamarin.Forms aufmerksam wurde. Der Leser bemerkte, dass ich im Beispielcode eine Verbindung im Konstruktor öffnete und diese dauerhaft geöffnet hielt, ohne Close oder Dispose aufzurufen. Der Leser befürchtete, dass dies zu Speicherlecks oder sogar Datenverlust führen könnte und wies darauf hin, dass in Foren oft empfohlen wird, Verbindungen nur kurz zu öffnen und sofort wieder zu schließen.
Der Livestream bringt am Mittwoch um 18 Uhr spannende Einblicke und Hintergründe zur enterJS, interessante Gespräche mit Gästen und ein Gewinnspiel.
.NET 7.0 bietet für Konsolen- und Webprojekte wieder den klassischen Startcode mit einer Programklasse inklusive Main()-Methode in den Projektvorlagen.
Is it possible to get YouTube Premium much cheaper with a VPN? Yes, as it turns out, YouTube Premium is offered at a very cheap price in Argentina. We’ll show you a simple trick that will let you enjoy YouTube Premium (without ads) at a much cheaper price. With a reliable VPN service, like the one from CyberGhost* or the slightly more expensive from ExpressVPN*, you can watch YouTube Premium for much cheaper. Just read on to find out how you can use the VPN service and why it’s the easiest (and safest) way to get YouTube Premium at a reasonable price.
YouTube Premium is very cheap in Argentina
YouTube advertising is really annoying. If you want to enjoy the video platform ad-free, you have to pay for YouTube Premium. However, prices vary depending on the country. In Germany, for example, YouTube charges a very high price per month for the Premium variant.
Let’s now take a look at the prices for YouTube Premium in Argentina:
Single tariff: 389 ARS / 2,12 Euro per month
Family tariff: 699 ARS / 3,82 Euro per month
Those Argentinien prices are way lower in comparison with most of the other countries. In Germany, for example, you have to pay 11.99 euros per month for the single rate. The family plan costs 17.99 euros per month. This is a significant saving that justifies the use of a VPN in any case.
How to use a VPN for YouTube Premium – a quick guide
If you want to take advantage of the low YouTube Premium prices in Argentina, you first need to create an account abroad. And this is where a VPN service comes in handy. With a VPN, you can go to virtually any country in the world and easily bypass digital country blocks.
Time needed: 15 minutes.
Follow these simple steps and watch YouTube Premium at a much lower price via a VPN server in Argentina:
- Choose a VPN
We recommend two trusted providers with good reputation – CyberGhost*. CyberGhost offers 48 servers in Argentina. Again, the speed is perfect for the purpose.
- Install the VPN app/client
Once you have chosen a VPN service, you should install the software and launch the program.
- Choose a server in Argentina
Open the app/client. Then open the server or country selector and choose Argentina. Once you have connected to the Argentine VPN server, go to the YouTube Premium website.
Check if you are really connected to the Argentine YouTube site – the YouTube logo should have the abbreviation “AR” in the upper left corner. The prices should be displayed in Argentine pesos (ARS).
- Create a new Google Account
You need a Google Account to get YouTube Premium. Create a new Google Account. You can set it up later as a secondary YouTube account. Go to the YouTube Premium homepage. Click Sign in and follow the steps to set up the new Google Account.
- Go to YouTube Premium
If you now have a new Google account, go back to the YouTube Premium home page. Again, make sure the VPN connection to Argentina is up. When you’re logged in, you should see your shortcode in a colored circle at the top right of the site. Now:
- Fill out the form
On the home page, click the Free Trial button for the Standard Package. For the Family Package click on the Family Membership link. Then click on Try for free.
You will see a form to fill out. Enter your billing address and credit card information. Important: Visa credit cards are no longer accepted, but you can use other credit cards. Enter an Argentine address. Choose a random address through Google Maps and make sure you enter the correct zip code and province. Complete your subscription by clicking the Buy button.
- From now on, enjoy YouTube Premium at a great price!
From now on, you can sign in with your new Google Account and enjoy YouTube Premium at a very affordable price.
YouTube Premium – The advantages
YouTube Premium means videos without ads. That’s a big plus, because we all know how annoying those ads can be. They can really ruin your online experience.
With the Premium subscription, you can also download on the go. So you can download videos and music quickly and easily. You also get background playback – the feature plays videos in the background without interruption, you can open another app or even turn off the screen.
YouTube Music Premium, YouTube Kids, and YouTube Originals are part of the Premium plan. YouTube Originals includes original movies, series, and live events. While these events, movies, and series can occasionally be seen on the YouTube Originals channel, only Premium members can enjoy them without ads, watch all episodes, and get access to interesting bonus material. You also get the YouTube Gaming app.
FAQs – Frequently Asked Questions
Is it legal to buy YouTube Premium in Argentina with a VPN? Subscribing to YouTube Premium in Argentina is perfectly legal, but you are still in violation of the provider’s terms of service. YouTube is aware that there are geographical restrictions. The platform requires its users not to provide inaccurate or misleading information to falsely impersonate residents of a country where the paid services are accessible. Violations of YouTube’s terms of use may result in account suspension or deletion.
Can I use a free VPN service for YouTube Premium in Argentina? It would work if you could find a VPN provider with reliable free servers in Argentina. I have not been able to do that.
If you use streaming platforms frequently, it would generally be a good idea to use a reliable paid VPN service like ExpressVPN* and CyberGhost*.
Why is YouTube Premium no longer an option for India? India offers cheap YouTube Premium prices. But because of some new laws in India, most of the top VPN providers have pulled out of the country. The new law requires VPNs to log their users’ traffic. VPNs like CyberGhost continue to operate servers with India as their geolocation, but in some cases these servers cannot be reliably cloaked. As a result, YouTube either detects that you’re using a VPN or displays incorrect prices.
The post YouTube Premium much cheaper with VPN Argentina appeared first on xplatform.rocks.
Are you wondering how to stream Russian TV over the Internet? I have a great news for you. You can do that with CyberGhost*! It is one of the few VPN providers that still operates servers in Russia.
With CyberGhost you can stream Russian TV over the Internet.
Quick guide: Watch Russian TV online
In order to watch all Russian TV online, you need a VPN that provides servers in Russia. So you need a Russian IP address. There are not so many of them anymore, because the legal situation in Russia regarding VPNs is questionable.
Time needed: 10 minutes.
How to get a Russian IP address outside of Russia to stream Russian TV
- Take a VPN with servers in Russia
One of the few VPN providers that still runs well-functioning servers in Russia is CyberGhost*. The good thing about the service is that it offers a money-back guarantee on the long-term package and is also one of the cheapest providers on the market.
- Install VPN apps
Consider on which devices you want to watch Russian TV. As with many VPNs, you can install CyberGhost on multiple devices and that’s why you can run it on your smartphone, laptop and tablet simultaneously. Currently, CyberGhost allows 7 simultaneous connections and that’s a lot. The VPN supports the most popular operating systems and devices: Android, Windows, iOS, macOS and Linux as well.
- Connect to a Russian server
For Russian TV programs you need a Russian IP address. Therefore, you need to connect to a server in Russia. Then you can stream Russian TV online. That’s it. That’s all you really need to do. It’s actually as simple as it sounds.
Stream better protected
Internet censorship and surveillance is a problem in Russia and therefore you can protect yourself better with a VPN. Your Internet traffic is encrypted by the VPN and no one except the VPN provider can see what you are doing online. Of course, you have to have a certain trust in your VPN provider.
CyberGhost has a no-logs policy and does not collect any data. That’s why it can’t share anything with authorities and third parties, even if the service is asked for it.
Russian broadcasters use geo-blocking and then you need a Russian IP address to watch the corresponding show.
These Russian channels work with VPN
Of course, we tested whether you can safely stream Russian TV over the Internet with a VPN. We took a look at the most popular services and platforms.
Important note: Some of the listed services and streams might be illegal. We could not 100% understand what is legal and illegal because we don’t speak the language and don’t know exactly what the law is. So please inform yourself what is legal and illegal in your country so that you don’t get into trouble!
A popular Russian sports channel is Match TV. There you can find Bundesliga, Premier League, Formula 1 and how to stream Champions League for free. There are many sports events that you can watch there for free in Russian. Match TV belongs to the Gazprom Group.
Among the most important Russian TV channels is ntv.ru (state TV channel from Moscow).
1TV.ru is the first channel of the semi-public Russian broadcaster Perwy. I was also able to watch this portal with CyberGhost* without any problems.
Equally interesting is Planeta-Online.tv. The online TV portal provides access to eight Russian TV channels.
Other streams and channels you can watch with a VPN
Here are a few more portals that work with a VPN, but they can be shady. Extreme caution is advised here, so that you don’t get into conflict with the law.
- Fubo TV
- Rutube
- TVCenter
- Okko
- STS
- Videomore
- TVZavr
- Russian VoD
- Kinopoisk
- Ren TV
- Amediateka
- Zoomby
- KinoPoisk HDTV
- TV-Novosty
- TV-Mania
- TV-Pressa
- NTV Plus
- YuppTV
- TV 1000
- TVCatchup
FAQ – Streaming Russian TV
Here are some answers to questions that interest you.
Can I stream Russian TV with a free VPN? I doubt it, at least for the shows that are geoblocked. I don’t know of any free VPN that offers servers in Russia. Even if they do, reputable free VPNs have severe limitations, such as data volume. Then you can only stream for a short time and the pleasure quickly comes to an end. The problem at this point is that there are many dubious free VPN providers that are not trustworthy. They collect and sell your data to third parties, and in the worst case, they install malware and trackers on your device. Reputable providers like CyberGhost are cheap and have no restrictions. Moreover, they offer functioning servers in Russia.
Does Russian streaming offer other languages? As far as I saw during my tests, you can’t switch to any other language. I was able to use the translation feature of the browsers to help me navigate the site more easily. However, the streaming, i.e. the comments and the language itself always remained Russian.
Which is the best Russian channel for sports? If you are interested in sports events such as the Champions League, Formula 1 and so on, then Match TV is definitely your first port of call. The other channels are interesting for you if you are interested in news or other Russian programs. So it depends on your needs what is the best Russian channel.
The post Stream Russian TV over the Internet appeared first on xplatform.rocks.
Inheritance is a popular method for reusing existing function blocks. It enables new methods and properties to be added or existing methods overwritten without requiring access to the source code for the base function block. Designing software so that it can be extended without modifying the existing code is the key concept behind the Open/Closed Principle (OCP). But using inheritance also has disadvantages. These disadvantages can be minimised by employing interfaces – and this is not the only advantage of this method.
To put it another way, software behaviour should be open to extension without needing to modify the software. Based on our example from my previous posts, we’re going to develop a function block for managing lamp control sequences. We will then add additional functionality to extend this function block. We will use this example to illustrate the key concept underlying the Open/Closed Principle (OCP).
Starting situation
Our main starting point is the function block FB_SequenceManager. This provides access to the individual steps in a sequence via the aSequence property. The Sort() method provides a means to sort the list in accordance with various criteria.
The aSequence property is an array and contains elements of type ST_SequenceItem.
PROPERTY PUBLIC aSequence : ARRAY [1..5] OF ST_SequenceItem
To keep our example simple, we define our array as having fixed upper and lower bounds of 1 and 5. Array elements are of type ST_SequenceItem, which contains a unique ID (nId), the output value for the lamps (nValue) and the duration (nDuration) before switching to the next output value.
TYPE ST_SequenceItem :
STRUCT
nId : UINT;
nValue : USINT(0..100);
nDuration : UINT;
END_STRUCT
END_TYPE
In this example, we will not concern ourselves with methods for processing the sequence. Our example does, however, include a Sort() method for sorting the list by various criteria.
METHOD PUBLIC Sort
VAR_INPUT
eSortedOrder : E_SortedOrder;
END_VAR
The list can be sorted in ascending order only by nId or nValue.
TYPE E_SortedOrder :
(
Id,
Value
);
END_TYPE
In the Sort() method, the eSortedOrder input parameter determines whether the list is sorted by nId or nValue.
CASE eSortedOrder OF
E_SortedOrder.Id:
// Sort the list by nId
// …
E_SortedOrder.Value:
// Sort the list by nValue
// …
END_CASE
Our example is a simple monolithic application which can be put together quickly to meet our requirements.
The UML diagram shows the monolithic structure of the application very clearly:
This does not, however, take account of the amount of work required to realise future extensions.
Sample 1 (TwinCAT 3.1.4024) on GitHub
Extension of the implementation
We are going to extend the application so that, in addition to nId and nValue, we can also sort the list by nDuration. Currently, the list is always sorted in ascending order. We would also like to be able to sort it in descending order.
How can we modify our example to meet these two client requirements?
Approach 1: Quick & dirty
One approach is to simply extend the existing Sort() method so it can also sort by nDuration. To do this, we add the field eDuration to E_SortedOrder.
TYPE E_SortedOrder :
(
Id,
Value,
Duration
);
END_TYPE
We also need a parameter to indicate whether we want to sort in ascending or descending order:
TYPE E_SortedDirection :
(
Ascending,
Descending
);
END_TYPE
So the Sort() method now takes two parameters:
METHOD PUBLIC Sort
VAR_INPUT
eSortedOrder : E_SortedOrder;
eSortedDirection : E_SortedDirection;
END_VAR
The Sort() method now contains two nested CASE statements. The outermost of these deals with the sort direction, the innermost with the parameter by which to sort the list.
CASE eSortedDirection OF
E_SortedDirection.Ascending:
CASE eSortedOrder OF
E_SortedOrder.Id:
// Sort the list by nId in ascending order
// …
E_SortedOrder.Value:
// Sort the list by nValue in ascending order
// …
E_SortedOrder.Duration:
// Sort the list by nDuration in ascending order
// …
END_CASE
E_SortedDirection.Descending:
CASE eSortedOrder OF
E_SortedOrder.Id:
// Sort the list by nId in descending order
// …
E_SortedOrder.Value:
// Sort the list by nValue in descending order
// …
E_SortedOrder.Duration:
// Sort the list by nDuration in descending order
// …
END_CASE
END_CASE
END_CASE
This approach is quick to implement. For a small application with a reasonably small amount of source code, this is absolutely a reasonable approach. But for this approach to be feasible, we have to have access to the source code. In addition, we need to ensure that FB_SequenceManager isn’t shared with other projects via, for example, a PLC library containing FB_SequenceManager. By adding a parameter to the Sort() method, we have also changed its signature. This means that program components that call this method with just a single parameter will no longer compile.
The UML diagram shows clearly that the structure is unchanged – it’s still a highly monolithic application:
Sample 2 (TwinCAT 3.1.4024) on GitHub
Approach 2: Inheritance
Another way to add features to the application is to use inheritance. This allows us to extend function blocks without having to modify the existing function block.
We start by creating a new function block which inherits from FB_SequenceManager:
FUNCTION_BLOCK PUBLIC FB_SequenceManagerEx EXTENDS FB_SequenceManager
The new function block contains a SortEx() method which takes two parameters specifying the required sort direction and order:
METHOD PUBLIC SortEx : BOOL
VAR_INPUT
eSortedOrder : E_SortedOrderEx;
eSortedDirection : E_SortedDirection;
END_VAR
Once again we add a data type E_SortedDirection which specifies whether the list should be sorted in ascending or descending order:
TYPE E_SortedDirection :
(
Ascending,
Descending
);
END_TYPE
Rather than extending E_SortedOrder, we create a new data type:
TYPE E_SortedOrderEx :
(
Id,
Value,
Duration
);
END_TYPE
We can now implement the required sort functions in the SortEx() method.
To sort in ascending order, we can use the Sort() method from the base function block (FB_SequenceManager). We don’t need to reimplement the existing sorting algorithm. All we need to do is add the additional sort type:
CASE eSortedOrder OF
E_SortedOrderEx.Id:
SUPER^.Sort(E_SortedOrder.Id);
E_SortedOrderEx.Value:
SUPER^.Sort(E_SortedOrder.Value);
E_SortedOrderEx.Duration:
// Sort the list by nDuration in ascending order
// …
END_CASE
Sorting in descending order needs to be programmed from scratch, however, as this cannot be achieved using existing methods.
If a new function block extends an existing function block, the new function block inherits the functionality of the base function block. The addition of further methods and properties enables it to be extended without needing to modify the base function block (open for extension). By using libraries, it’s also possible to protect the source code from modification (closed for modification).
Inheritance is therefore one way of implementing the Open/Closed Principle (OCP).
Sample 3 (TwinCAT 3.1.4024) on GitHub
This approach does, however, have two disadvantages.
Excessive use of inheritance can end up generating complex hierarchies. A child function block is absolutely dependent on its base function block. If new methods or properties are added to the base function block, every child function block will also inherit these new elements (if they are PUBLIC), even if the child function block has no intention of exposing these elements externally.
In some circumstances, extension by inheritance is only possible where the child function block has access to internal state information from the base function block. Access to these internal elements can be enabled by marking them as PROTECTED. This restricts access to child function blocks only.
In the example given above, the only reason we were able to add the sorting algorithms was because the setter for the aSequence property was declared as PROTECTED. If we did not have write access to the aSequence property, the child function block would not be able to modify the list, so would not be able to sort it.
This means, however, that the developer coding this function block always has to take into consideration two use cases. Firstly, a user making use of the function block’s public methods and properties. Secondly, users using the function block as a base function block and adding new functionality via PROTECTED elements. But which internal elements need to be marked as PROTECTED? And to enable their use, these elements also need to be documented.
Approach 3: Additional interface
Another approach is to use interfaces rather than inheritance. This, however, needs to be considered during the design phase.
If our aim is to design FB_SequenceManager so that users can add whatever sorting algorithms they want, then we should remove the code for sorting the list. The sorting algorithm should instead access the list via an interface.
In our example, we would add the interface I_SequenceSortable. This interface contains the SortList() method, which contains a reference to the list to be sorted.
METHOD SortList
VAR_INPUT
refSequence : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR
Next we create the function blocks containing the various sorting algorithms, each of which implements the I_SequenceSortable interface. As an example, we will take the function block for sorting by nId in ascending order.
FUNCTION_BLOCK PUBLIC FB_SequenceSortedByIdAscending IMPLEMENTS I_SequenceSortable
We can call the function block whatever we want; the crucial point is that it implements the I_SequenceSortable interface. This ensures that FB_SequenceSortedByIdAscending contains the SortList() method. The actual sorting algorithm is implemented in the SortList() method.
METHOD SortList
VAR_INPUT
refSequence : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR
// Sort the list by nId in ascending order
// …
The Sort() method of FB_SequenceManager takes a parameter of type I_SequenceSortable. When calling the Sort() method we pass to it a function block (e.g. FB_SequenceSortedByIdAscending) which implements the I_SequenceSortable interface and therefore also contains the SortList() method. FB_SequenceManager’s Sort() method calls SortList() and passes to it a reference to the aSequence list.
METHOD PUBLIC Sort
VAR_INPUT
ipSequenceSortable : I_SequenceSortable;
END_VAR
IF (ipSequenceSortable <> 0) THEN
ipSequenceSortable.SortList(THIS^._aSequence);
END_IF
This means that a reference to the list to be sorted is passed to the function block containing the implemented sorting algorithm.
We create a separate function block for each sorting algorithm. This means we have access both to FB_SequenceManager containing the Sort() method, and to function blocks containing the sorting algorithms and implementing the I_SequenceSortable interface.
When it calls the Sort() method, FB_SequenceManager passes to it a function block (in our case FB_SequenceSortedByIdAscending). This function block contains the I_SequenceSortable interface subsequently used to call the SortList() method.
PROGRAM MAIN
VAR
fbSequenceManager : FB_SequenceManager;
fbSequenceSortedByIdAscending : FB_SequenceSortedByIdAscending;
// …
END_VAR
fbSequenceManager.Sort(fbSequenceSortedByIdAscending);
// …
This approach avoids the use of inheritance. The sorting algorithm function blocks could employ their own inheritance hierarchy if required. These function blocks could also implement additional interfaces, since it is possible to implement multiple interfaces.
Using this interface realises a clear separation between data storage (the list) and data processing (sorting). The aSequence property does not need write access. We also avoid the need to access internal FB_SequenceManager variables.
In addition, we no longer need the E_SortedOrder and E_SortedDirection data types. The sort type is determined solely by which function block we pass to Sort().
We can also add new sorting algorithms without needing to modify or change existing elements.
Sample 4 (TwinCAT 3.1.4024) on GitHub
Optimization analysis
There are various methods for extending the functionally of an existing function block without having to modify it. As well as inheritance – a key feature of object-oriented programming (OOP) – interfaces may provide a better alternative.
Using interfaces brings greater decoupling. But the individual interfaces do have to be implemented in the software design. This means that we need to consider in advance which areas need to be abstracted via interfaces and which don’t.
With inheritance too, when we develop a function block we have to consider which internal elements should be made accessible (by using the PROTECTED keyword) to function blocks derived from it.
The definition of the Open/Closed Principle
The Open/Closed Principle (OCP) was originated in 1988 by Bertrand Meyer. It states:
Software entities should be open for extension, but closed for modification.
Software entity: This means a class, function block, module, method, service, etc.
Open: The behaviour of a software entity should be able to be extended.
Closed: This extensibility should not be achieved by modifying existing software.
When Bertrand Meyer defined the Open/Closed Principle (OCP) in the late 1980s, the focus was on C++ as a programming language. He used the concept of inheritance, a familiar concept in the object-oriented programming world. Object-orientated programming – at the time a fairly young discipline – was seen as promising big improvements in terms of reusability and maintainability as a result of the ability to reuse classes as base classes for new classes.
When Robert C. Martin took up Meyer’s principle in the 1990s, he took a different approach to its technical implementation. C++ allows the use of multiple inheritance, which is rare in more recent programming languages. Consequently, Robert C. Martin focused on the use of interfaces. More information can be found in his book (Amazon ad link *) Clean Architecture: A Craftsman’s Guide to Software Structure and Design.
Summary
Adhering to the Open/Closed Principle (OCP) does carry a risk of overengineering. We should only implement extensibility where it is actually needed. It is impossible to design software so that every conceivable extension can be implemented without needing to modify the source code.
This concludes my series of posts on SOLID principles. Other principles are of course available, including Keep It Simple, Stupid (KISS), Don’t Repeat Yourself (DRY), Law Of Demeter (LOD) and You Ain’t Gonna Need It (YAGNI). What all these principles have in common is the goal of making software more maintainable and more reusable.
Das aktuelle .NET-Release zeigt Vorschläge für Befehle im Kommandozeilenfenster. Die Autovervollständigung muss man allerdings zunächst aktivieren.
For about a year, I was working on a pretty exciting project. I defined and created a new role for our company that is responsible for application security. Actually, application security was never a missing aspect of our development process. All my colleagues were great developers and highly motivated to create secure applications.
The actual problem was a missing standard, that sets up every project in the same secure way, which helps the QA to also test security aspects, use the same tools to improve the software quality and software security and keep the awareness on security during the entire development process.
Defining the new role
Defining and creating this new role also means that I will take over this new role and be responsible, to ensure and to maintain the security standards throughout the entire company. I will also be responsible to keep awareness about security throughout the entire company and to train the developers, the DevOps responsible person as well as the QA. I am not the only person that is responsible for application security in general. My job will be to make all colleagues feel responsible to create secure applications. That they all have security in mind, that all features will be analyzed from the security perspective as well.
And this is why the process of secure software development doesn't start with development or DevOps.
Adding security to the company
Actually, the secure software development process starts at the sales phase. The salesperson needs to know what type of customer he is selling our services to, what type of data the potential customer will be handle with the new project, and what type of possible risks there are. The salesperson needs to know what level of security he needs to sell. (Exactly, we need to sell security. See next section why)
The process continues with the requirements engineering, even the UX and UI specialists need to take care of security. DevOps is following, by setting up the secure software development infrastructure and secure deployments per project. DevOps is also supporting the developers with the right tools that check for software quality and possible vulnerabilities and code flaws while building and delivering the software. In the development phase, required security aspects need to be implemented and QA needs to know how to test this. Maybe tooling will support the QA to make automated security tests.
Selling security
True, we need to sell levels of security because ensuring application security needs some effort. The more secure the more effort during development and afterward, while ensuring and testing the application security. A potential customer in a sensitive or risky environment should know that security is not for free. A bank, a power plant, and other big and risky industry are paying for security personnel that keeps unauthorized people outside of their restricted areas. Such companies should be aware and willing to pay for implementing higher security mechanisms to keep unauthorized people out of their digitally restricted areas as well.
Actually, application security needs to be ensured in every project and the basic level of security won't be charged separately.
What are the standards we use?
It is the OWASP foundation that helps me dive into new topics. We are going to implement the OWAS Application Security Verification Standard (ASVS) and the mobile version of it (MASVS). ASVS already is divided into three levels of security. Level 1 is the basic level of security that all projects need to implement. Actually, Level 1 is quite basic and despite just a few topics, this is all stuff we as developers almost already knew, used, and implemented in the past. If we have thought about it and if the project pressure wasn't that high. Levels 2 and 3 are adding more security mechanisms to the projects to handle sensitive and critical data and infrastructure.
This standard is helping us like a blueprint for all our projects to keep the levels of security and it helps our QA to know what to test from the security point of view.
Actually, since ASVS is adopting and covering many other standards as well, we will be safe with future security audits, no matter what standard will be used during a possible audit.
Will YOO be a secure software company?
The company already creates secure software. Since it was more or less a side aspect in the past, we'll now focus on security by following the standards and the process we have implemented.
So, yes, we can now call ourselves a secure software company. But we are not certified somehow. OWASP and ASVS are no badges nor provide certificates we can put proudly and high-nosed on our website. But we can proudly mention that we are following a standard that was created by well-known and independent security experts.
My main role is still a software engineer :-)
The application security role is only an additional role to my position as a software engineer. In a midsized company like the YOO ensuring secure software is not such a high effort that it is needed to create a new position like an application security engineer. And therefore it is just a new additional role for me.
Despite that, my job title will change a little bit and will be called Software & AppSec Engineer.
Learning about application security
Actually, application security as a global topic was kinda new to me and I never expected that it is needed to have the entire company involved. But that also was the fun part: Talking to other disciplines and talking to people that are not really involved in my day-to-day business. It is not completely technical to implement application security in a software company.
As mentioned, the website of the OWASP Foundation points me to various learning resources. OWASP is full of projects to learn about application security. You might know the OWASP Top 10 list of security risks. I already mentioned the ASVS. But there is a ton more.
Another great learning resource is the Twitter feed of Tanya Janka. Her talks about application security are amazing and her book is a great read, even on vacation at the beaches of Greece while the kids are playing:

If you want to learn about application security, follow her on Twitter, read her blog, read her book, and watch her talks. You also need to dive into the OWASP website and the various projects of the foundation.
Furthermore
And maybe, you as a software-producing company would like to adopt the same standards and processes. If you would like to know, how we created and implemented the secure software process, feel free to ask. If you need help to make your software development process more secure, we would be happy to help as well.
Learn more: https://www.yoo.digital/applicationsecurity
Conclusion
I'm happy to start working on my new role officially this week and I'm happy to bring the YOO a step further in creating and delivering high-quality and secure software. I'm also pretty excited about how it will go and grow over time. The implementation of a secure software process will never be complete and needs to be adjusted whenever it's needed. It is a living process that needs reviews and adjustments regularly.
.NET 6.0 hat einige generische Mathematikoperationen für beliebige Zahlentypen eingeführt, die im aktuellen .NET produktionsreif sind.
Die jüngste C#-Version ermöglicht das Überladen von Operatoren nicht nur in Klassen, sondern auch in Interfaces.
The AI world is rising very fast these days: ChatGPT is such an awesome (and scary good?) service and Microsoft joined the ship with some partner announcements and investments. The result is of these actions is, that OpenAI is now a “first class citizen” on Azure.
So - for the average Microsoft/.NET developer this opens up a wonderful toolbox and the first steps are really easy.
Be aware: You need to “apply” to access the OpenAI service, but it took less then 24 hours for us to gain access to the service. I guess this is just a temporary thing.
Disclaimer: I’m not an AI/ML engineer and I only have a very “glimpse” knowledge about the technology behind GPT3, ChatGPT and ML in general. If in doubt, I always ask my buddy Oliver Guhr, because he is much smarter in this stuff. Follow him on Twitter!
1. Step: Go to Azure OpenAI Service
Search for “OpenAI” and you will see the “Azure OpenAI Service” entry:

2. Step: Create a Azure OpenAI Service instance
Create a new Azure OpenAI Service instance:

On the next page you will need to enter the subscription, resource group, region and a name (typical Azure stuff):

Be aware: If your subscription is not enabled for OpenAI, you need to apply here first.
3. Step: Overview and create a model
After the service is created you should see something like this:

Now go to “Model deployments” and create a model - I choosed “text-davinci-003”, because I think this is GPT3.5 (which was the initial ChatGPT release, GPT4 is currently in preview for Azure and you need to apply again.

My guess is, that you could train/deploy other, specialized models here, because this model is quite complex and you might want to tailor the model for your scenario to get faster/cheaper results… but I honestly don’t know how to do it (currently), so we just leave the default.
4. Step: Get the endpoint and the key
In this step we just need to copy the key and the endpoint, which can be found under “Keys and Endpoint”, simple - right?

5. Step: Hello World to our Azure OpenAI instance
Create a .NET application and add the Azure.AI.OpenAI NuGet package (currently in preview!).
dotnet add package Azure.AI.OpenAI --version 1.0.0-beta.5
Use this code:
using Azure.AI.OpenAI;
using Azure;
Console.WriteLine("Hello, World!");
OpenAIClient client = new OpenAIClient(
new Uri("YOUR-ENDPOINT"),
new AzureKeyCredential("YOUR-KEY"));
string deploymentName = "text-davinci-003";
string prompt = "Tell us something about .NET development.";
Console.Write($"Input: {prompt}");
Response<Completions> completionsResponse = client.GetCompletions(deploymentName, prompt);
string completion = completionsResponse.Value.Choices[0].Text;
Console.WriteLine(completion);
Console.ReadLine();
Result:
Hello, World!
Input: Tell us something about .NET development.
.NET development is a mature, feature-rich platform that enables developers to create sophisticated web applications, services, and applications for desktop, mobile, and embedded systems. Its features include full-stack programming, object-oriented data structures, security, scalability, speed, and an open source framework for distributed applications. A great advantage of .NET development is its capability to develop applications for both Windows and Linux (using .NET Core). .NET development is also compatible with other languages such as
As you can see… the result is cut off, not sure why, but this is just a simple demonstration.
Summary
With these basic steps you can access the OpenAI development world. Azure makes it easy to integrate in your existing Azure/Microsoft “stack”. Be aware, that you could also use the same SDK and use the endpoint from OpenAI. Because of billing reasons it is easier for us to use the Azure hosted instances.
Hope this helps!
Video on my YouTube Channel
If you understand German and want to see it in action, check out my video on my Channel:
In our product we can interact with different datasource and one of these datasources was a Microsoft Access DB connected via OLEDB
. This is really, really old, but still works, but on one customer machine we had this issue:
'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine
Solution
If you face this issue, you need to install the provider from here.
Be aware: If you have a different error, you might need to install the newer provider - this is labled as “2010 Redistributable”, but still works with all those fancy Office 365 apps out there.
Important: You need to install the provider in the correct bit version, e.g. if you run under x64, install the x64.msi.
The solution comes from this Stackoverflow question.
Helper
The best tip from Stackoverflow was these powershell commands to check, if the provider is there or not:
(New-Object system.data.oledb.oledbenumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION
Get-OdbcDriver | select Name,Platform
This will return something like this:
PS C:\Users\muehsig> (New-Object system.data.oledb.oledbenumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION
SOURCES_NAME SOURCES_DESCRIPTION
------------ -------------------
SQLOLEDB Microsoft OLE DB Provider for SQL Server
MSDataShape MSDataShape
Microsoft.ACE.OLEDB.12.0 Microsoft Office 12.0 Access Database Engine OLE DB Provider
Microsoft.ACE.OLEDB.16.0 Microsoft Office 16.0 Access Database Engine OLE DB Provider
ADsDSOObject OLE DB Provider for Microsoft Directory Services
Windows Search Data Source Microsoft OLE DB Provider for Search
MSDASQL Microsoft OLE DB Provider for ODBC Drivers
MSDASQL Enumerator Microsoft OLE DB Enumerator for ODBC Drivers
SQLOLEDB Enumerator Microsoft OLE DB Enumerator for SQL Server
MSDAOSP Microsoft OLE DB Simple Provider
PS C:\Users\muehsig> Get-OdbcDriver | select Name,Platform
Name Platform
---- --------
Driver da Microsoft para arquivos texto (*.txt; *.csv) 32-bit
Driver do Microsoft Access (*.mdb) 32-bit
Driver do Microsoft dBase (*.dbf) 32-bit
Driver do Microsoft Excel(*.xls) 32-bit
Driver do Microsoft Paradox (*.db ) 32-bit
Microsoft Access Driver (*.mdb) 32-bit
Microsoft Access-Treiber (*.mdb) 32-bit
Microsoft dBase Driver (*.dbf) 32-bit
Microsoft dBase-Treiber (*.dbf) 32-bit
Microsoft Excel Driver (*.xls) 32-bit
Microsoft Excel-Treiber (*.xls) 32-bit
Microsoft ODBC for Oracle 32-bit
Microsoft Paradox Driver (*.db ) 32-bit
Microsoft Paradox-Treiber (*.db ) 32-bit
Microsoft Text Driver (*.txt; *.csv) 32-bit
Microsoft Text-Treiber (*.txt; *.csv) 32-bit
SQL Server 32-bit
ODBC Driver 17 for SQL Server 32-bit
SQL Server 64-bit
ODBC Driver 17 for SQL Server 64-bit
Microsoft Access Driver (*.mdb, *.accdb) 64-bit
Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) 64-bit
Microsoft Access Text Driver (*.txt, *.csv) 64-bit
Hope this helps! (And I hope you don’t need to deal with these ancient technologies for too long 😅)
Mobile apps thrive on an appealing and well-structured design that helps users achieve their goals. In this article, I'll show you how an old app design can be redesigned to make it look modern and clean. You'll learn more about the design process and design decisions made to provide users with a user-centric UI and UX that helps them achieve their goals.
Stellenanzeigen gleichen sich üblicherweise wie ein Ei dem anderen, statt den ersten individuellen Eindruck zu vermitteln, den man von einem Unternehmen erhält.
Every now and then you’ll try to watch a movie trailer or a music video on YouTube only to see this message: “This video is not available in your country”. And that can really spoil the fun. But here’s the good news: There is a way to watch blocked youtube videos from anywhere. If you get a reliable VPN service like CyberGhost*, blocked YouTube videos won’t be a problem anymore. VPNs give you access to different geo-locations. Switching countries (virtually) will allow you to watch geo-blocked YouTube videos. VPNs will also encrypt your connection, making it private and secure. So, you can easily watch blocked YouTube videos with a VPN. Let’s see how it works…
Why Are Some YouTube videos blocked?
YouTube is that massively popular video-sharing platform where you can watch tons of interesting stuff. The billion users can watch, like, subscribe, comment, upload and share videos, and it’s completely free. However, as we have already mentioned, you might encounter annoying geo-restrictions.
The site has licensed content including TV shows, movies and even music videos. Some of them are only licensed for specific countries. YouTube is truly heavily restricted in some parts of the world. For example, the popular video platform is completely blocked in Iran, China, Pakistan and North Korea. There can also be other explanations for why certain YouTube videos are inaccessible.
So, in brief, here are the most common reasons why some YouTube videos might be blocked:
- Licensing Rights – copyright laws or other laws regarding content distribution have placed restrictions covering certain countries or regions.
- Censorship – Some strict countries apply censorship on online content. YouTube can be blocked entirely or partially, depending on the local laws.
- Network Blocks – YouTube can be blocked because of the Network blocks on offices or school properties.
How to unblock YouTube videos in your country – A quick guide
VPN usage is without a doubt the most secure and effective way to get around the region filter and watch blocked videos on YouTube. A trustworthy VPN service will allow you to safely browse the web as if you were in a different country. The VPN will trick the blocked site, in this case it’s YouTube, by masking your local IP address and temporarily changing it. YouTube will assume that you are accessing it from a foreign country.
Time needed: 15 minutes.
Just follow these steps and you’ll be able to watch blocked YouTube videos in no time:
- Get a good VPN
Our top choice is CyberGhost*,a reliable VPN services with a great reputation. You can try using a free VPN but we definitely won’t recommend that option. It’s not really trustworthy and safe.
- Download and install the app
You’ve chosen a VPN? Great, install it and open the app/client.now connect to a server in the correct region. You have to make sure your traffic is being routed through your VPN. Open up the VPN app and toggle it on.
- Go to YouTube and find the video you want to unblock
It’s time to head to YouTube. Open your YouTube app or go to www.youtube.com. Find the blocked video that you want to watch. If the video is allowed in your VPN’s region, you’ll be allowed to watch it. If it doesn’t then you should check your VPN’s regional settings.
- Enjoy YouTube’s content!
That’s it! It’s a really fast and simple trick that will save you a lot of headaches.
VPN for YouTube: The most important features
How to choose the right VPN to unblock YouTube videos? Here are the most important features to look out for:
- The speed of the service: You will need fast server speeds in order to stream YouTube videos smoothly. It’s essential to choose a VPN that offers fast speeds.
- Security credentials: If you’re in a country that has banned YouTube, you’ll want to make sure you have chosen a virtual private network that will protect your online identity. Reputable VPN services offer good security features that will keep you more anonymous.
- The devices it supports: If you’re planning to watch YouTube videos on your smart TV, streaming stick, mobile phone or games console, make sure that your chosen VPN works on all of the devices you’re wanting to use.
- The reputation: Why do people always search for the reviews of all sorts of products? Because a good advice and opinion from someone who has already tried a certain product/service is always helpful. It can guide you in your decision making process. It’s important to get a VPN that has a good reputation and a solid customer support.

About CyberGhost – Watch blocked YouTube videos with CyberGhost
So why is CyberGhost* our top recommendation?
CyberGhost is based in Romania and boasts a plethora of excellent security features that you can fully trust. With this provider, you’ll have access to top-notch encryption (AES 256-bit), split tunneling, integrated ad, and malware protection, SmartDNS, private DNS, and even an automatic kill-switch to safeguard your online activities if your VPN connection unexpectedly drops. The service also operates over 6,000 servers across the globe.
A crucial element to note is the stringent No-Logs policy that CyberGhost adheres to. This means that CyberGhost neither retains nor tracks your data. There’s no data storage or sharing – your digital footprint stays yours alone. Hence, CyberGhost becomes an ideal choice for those who are anxious about government surveillance and censorship, those who seek anonymity and privacy, and those who simply desire a safe and secure online experience.
FAQ – Frequently Asked Questions
Why is my YouTube video blocked? Some YouTube videos may be unavailable because video owners have chosen to make their content available only to certain countries/regions due to licensing rights. YouTube can also block certain content to comply with local laws. The governments in some countries can block videos because of censorship. For example, a certain video might be at odds with a country’s culture and beliefs. So, it will be blocked.
Sometimes, even offices and schools would ban YouTube. That’s because if employees and students are able to watch videos during their work hours they won’t be focused and productive.
How do I unblock YouTube videos? A trustworthy VPN with a flawless reputation is the best way to enjoy blocked YouTube videos. Get a VPN browser extension, select any country and try opening the video. VPNs hide your real IP address, temporarily replacing it with an address from the country you have selected. That’s an easy way to bypass any geological restrictions that a YouTube video might have.
Is unblocking YouTube safe? Yes, it should be perfectly safe when you’re using a dependable VPN service. And not only will a virtual private network (VPN) unblock any YouTube video, so you can watch it without a problem, but it will also encrypt everything you do on the internet. That means you can remain completely anonymous, keep your online activities private and stay protected from hackers and other third party snoopers.
The post Watch blocked youtube videos with a VPN appeared first on xplatform.rocks.
I was playing around with some Visual Studio Tooling and noticed this error during the creation of a “Azure Container Apps”-app:
Resource type is not supported in this subscription

Solution
The solution is quite strange at first, but in the super configurable world of Azure it makes sense: You need to activate the Resource provider for this feature on your subscription. For Azure Container Apps
you need the Microsoft.ContainerRegistry
-resource provider registered:

It seems, that you can create such resources via the Portal, but if you go via the API (which Visual Studio seems to do) the provider needs to be registered at first.
Some resource providers are “enabled by default”, other providers needs to be turned on manually. Check out this list for a list of all resource providers and the related Azure service.
Be careful: I guess you should only enable the resource providers that you really need, otherwise your attack surface will get larger.
To be honest: This was completly new for me - I do Azure since ages and never had to deal with resource providers. Always learning ;)
Hope this helps!
In der neuen Version von Microsofts Programmiersprache C# dürfen Schnittstellendeklarationen von Properties und Methoden als static abstract deklariert sein.
Vererbung ist eine beliebte Methode, um bestehende Funktionsblöcke wiederzuverwenden. Dadurch lassen sich Methoden und Eigenschaften hinzufügen oder bestehende Methoden überschreiben. Hierbei ist es nicht notwendig, den Quellcode des Basis-FB zur Verfügung zu haben. Software so zu designen, dass Erweiterungen möglich sind, ohne die vorhandene Software zu verändern, ist die Grundidee des Open/Closed Principle (OCP). Doch die Anwendung von Vererbung hat hierbei auch Nachteile. Der Einsatz von Schnittstellen minimiert diese Nachteile und bietet zusätzliche Vorteile.
Mit anderen Worten: Das Verhalten von Software sollte erweiterbar sein, ohne dass sie modifiziert werden muss. Angelehnt an das Beispiel aus den bisherigen Posts, soll ein Funktionsblock entwickelt werden, um Sequenzen für die Ansteuerung von Lampen zu verwalten. Anschließend wird der Funktionsblock um zusätzliche Funktionen erweitert. Anhand dieses Beispiels wird die Grundidee des Open/Closed Principle (OCP) genauer betrachtet.
Ausgangssituation
Zentraler Ausgangspunkt ist der Funktionsblock FB_SequenceManager. Dieser stellt über die Eigenschaft aSequence die einzelnen Schritte einer Sequenz zur Verfügung. Über die Methode Sort() kann die Liste nach verschiedenen Kriterien sortiert werden.
Die Eigenschaft aSequence ist ein Array und enthält Elemente vom Typ ST_SequenceItem.
PROPERTY PUBLIC aSequence : ARRAY [1..5] OF ST_SequenceItem
Um das Beispiel überschaubar zu halten, wird mit festen Arraygrenzen von 1 bis 5 gearbeitet. Die Array-Elemente sind vom Typ ST_SequenceItem und enthalten eine eindeutige Id (nId), den Ausgangswert (nValue) für die Lampen und die Dauer (nDuration) bis zum Umschalten auf den nächsten Ausgangswert.
TYPE ST_SequenceItem :
STRUCT
nId : UINT;
nValue : USINT(0..100);
nDuration : UINT;
END_STRUCT
END_TYPE
Auf sämtliche Methoden für die Bearbeitung der Sequenz wurde im Rahmen dieses Beispiels verzichtet. Allerdings enthält das Beispiel die Methode Sort(), um die Liste nach verschiedenen Kriterien zu sortieren.
METHOD PUBLIC Sort
VAR_INPUT
eSortedOrder : E_SortedOrder;
END_VAR
Die Liste kann aufsteigend nach nId oder nValue sortiert werden.
TYPE E_SortedOrder :
(
Id,
Value
);
END_TYPE
In der Methode Sort() wird durch den Eingangsparameter eSortedOrder entschieden, ob nach nId oder nach nValue sortiert werden soll.
CASE eSortedOrder OF
E_SortedOrder.Id:
// Sort the list by nId
// …
E_SortedOrder.Value:
// Sort the list by nValue
// …
END_CASE
Bei dem Beispiel handelt es sich um eine einfache monolithische Anwendung, welche in kurzer Zeit erstellt werden kann, um die gewünschten Anforderungen zu erfüllen.
Das UML-Diagramm zeigt recht deutlich den monolithischen Aufbau der Anwendung:
Dabei wurde allerdings nicht berücksichtigt, mit welchem Aufwand zukünftige Erweiterungen realisierbar sind.
Beispiel 1 (TwinCAT 3.1.4024) auf GitHub
Erweiterung der Implementierung
Die Anwendung soll so erweitert werden, dass nicht nur nach nId und nValue sortiert werden kann, sondern auch zusätzlich nach nDuration. Bisher wurde die Liste immer aufsteigend sortiert. Eine absteigende Sortierung ist ebenfalls gewünscht.
Wie lässt sich unser Beispiel anpassen, damit die beiden Kundenwünsche erfüllt werden?
Ansatz 1: Quick & Dirty
Ein Ansatz besteht darin, die vorhandene Methode Sort() einfach zu erweitern, so dass diese auch nach nDuration sortieren kann. Hierzu wird E_SortedOrder um das Feld eDuration erweitert.
TYPE E_SortedOrder :
(
Id,
Value,
Duration
);
END_TYPE
Zusätzlich wird noch ein Parameter benötigt, der angibt ob in aufsteigender oder in absteigender Reihenfolge sortiert werden soll:
TYPE E_SortedDirection :
(
Ascending,
Descending
);
END_TYPE
Somit besitzt die Methode Sort() jetzt zwei Parameter:
METHOD PUBLIC Sort
VAR_INPUT
eSortedOrder : E_SortedOrder;
eSortedDirection : E_SortedDirection;
END_VAR
Die Methode Sort() enthält jetzt zwei ineinander verschachtelte CASE-Anweisungen. Die Äußere für die Auswahl der Sortierrichtung und die Innere für das Element nach dem sortiert wird.
CASE eSortedDirection OF
E_SortedDirection.Ascending:
CASE eSortedOrder OF
E_SortedOrder.Id:
// Sort the list by nId in ascending order
// …
E_SortedOrder.Value:
// Sort the list by nValue in ascending order
// …
E_SortedOrder.Duration:
// Sort the list by nDuration in ascending order
// …
END_CASE
E_SortedDirection.Descending:
CASE eSortedOrder OF
E_SortedOrder.Id:
// Sort the list by nId in descending order
// …
E_SortedOrder.Value:
// Sort the list by nValue in descending order
// …
E_SortedOrder.Duration:
// Sort the list by nDuration in descending order
// …
END_CASE
END_CASE
END_CASE
Dieser Ansatz ist schnell umzusetzen. Bei einer kleinen Anwendung, wo der Quellcode nicht sehr umfangreich ist, durchaus ein guter Ansatz. Allerdings muss der Quellcode zur Verfügung stehen, damit diese Erweiterungen überhaupt möglich sind. Außerdem muss sichergestellt sein, dass FB_SequenceManager nicht mit anderen Projekten geteilt wird, z. B. durch eine SPS-Bibliothek in der FB_SequenceManager enthalten ist. Da bei der Methode Sort() ein Parameter hinzugekommen ist, hat sich die Signatur geändert. Programmteile, die die Methode mit einem Parameter aufrufen, lassen sich dadurch nicht mehr compilieren.
Durch das UML-Diagramm ist gut zu erkennen, dass sich die Struktur nicht geändert hat. Es ist weiterhin eine sehr monolithische Anwendung:
Beispiel 2 (TwinCAT 3.1.4024) auf GitHub
Ansatz 2: Vererbung
Ein weiterer Ansatz, um die Anwendung mit den gewünschten Funktionen zu erweitern, ist der Einsatz von Vererbung. Dadurch lassen sich Funktionsblöcke erweitern, ohne dass der vorhandene Funktionsblock verändert werden muss.
Hierzu wird als erstes ein neuer Funktionsblock angelegt, der von FB_SequenceManager erbt:
FUNCTION_BLOCK PUBLIC FB_SequenceManagerEx EXTENDS FB_SequenceManager
Der neue Funktionsblock erhält die Methode SortEx(), mit den beiden Parametern, welche die gewünschte Sortierung vorgibt:
METHOD PUBLIC SortEx : BOOL
VAR_INPUT
eSortedOrder : E_SortedOrderEx;
eSortedDirection : E_SortedDirection;
END_VAR
Auch hier wird wieder der Datentyp E_SortedDirection hinzugefügt, der angibt ob in aufsteigender oder in absteigender Reihenfolge sortiert werden soll:
TYPE E_SortedDirection :
(
Ascending,
Descending
);
END_TYPE
Statt E_SortedOrder zu erweitern, wir ein neuer Datentyp angelegt:
TYPE E_SortedOrderEx :
(
Id,
Value,
Duration
);
END_TYPE
In der Methode SortEx() können jetzt die gewünschten Sortierungen umgesetzt werden.
Bei der Sortierung in aufsteigender Reihenfolge ist der Zugriff auf die Methode Sort() des Basis-FBs (FB_SequenceManager) möglich. Dadurch ist eine erneute Implementierung der schon vorhandenen Sortieralgorithmen nicht erforderlich. Nur die zusätzliche Sortierung muss hinzugefügt werden:
CASE eSortedOrder OF
E_SortedOrderEx.Id:
SUPER^.Sort(E_SortedOrder.Id);
E_SortedOrderEx.Value:
SUPER^.Sort(E_SortedOrder.Value);
E_SortedOrderEx.Duration:
// Sort the list by nDuration in ascending order
// …
END_CASE
Die Sortierung in absteigender Reihenfolge muss allerdings komplett programmiert werden, da hier nicht auf bestehende Methoden zurückgegriffen werden kann.
Erbt ein Funktionsblock von einem anderen Funktionsblock, so erhält der neue Funktionsblock den Funktionsumfang des Basis-FBs. Durch zusätzliche Methoden und Eigenschaften kann dieser erweitert werden, ohne die Notwendigkeit, den Basis-FB zu verändern (offen für Erweiterungen). Durch den Einsatz von Bibliotheken kann der Quellcode auch komplett vor Veränderung geschützt werden (geschlossen gegen Modifikationen).
Vererbung ist somit eine Methode, um das Open/Closed Principle (OCP) umzusetzen.
Beispiel 3 (TwinCAT 3.1.4024) auf GitHub
Dieser Ansatz hat allerdings zwei Nachteile:
Durch den übermäßigen Einsatz von Vererbung können komplexe Hierarchien entstehen. Ein abgeleiteter FB ist fest an seinen Basis-FB gebunden. Wird der Basis-FB um weitere Methoden oder Eigenschaften erweitert, so erbt auch jeder abgeleitete FB diese Elemente (wenn diese PUBLIC sind), auch dann, wenn der abgeleitete FB diese Elemente nach Außen gar nicht anbieten möchte.
Eine Erweiterung durch Vererbung ist unter Umständen nur dann möglich, wenn die abgeleiteten Funktionsblöcke auf die internen Zustände des Basis-FBs Zugriff haben. Der Zugriff auf diese internen Elemente kann durch PROTECTED gekennzeichnet werden. Somit können nur abgeleitete Funktionsblöcke darauf zugreifen.
Im obigen Beispiel konnten nur deshalb die Sortieralgorithmen hinzugefügt werden, weil der Setter der Eigenschaft aSequence als PROTECTED deklariert wurde. Wäre ein Schreibzugriff auf die Eigenschaft aSequence nicht möglich, so könnte der abgeleitete Funktionsblock die Liste nicht verändern und somit auch nicht sortieren.
Dieses bedeutet aber, dass der Entwickler dieses Funktionsblocks immer zwei Anwendungsfälle berücksichtigen muss. Zum einen den Anwender, der die öffentlichen Methoden und Eigenschaften verwendet. Zusätzlich aber noch den Anwender, der den Funktionsblock als Basis-FB verwendet und auch über die PROTECTED Elemente neue Funktionalitäten hinzufügt. Doch welche internen Elemente sollen als PROTECTED markiert werden? Auch müssen diese Elemente dokumentiert werden, damit eine Anwendung überhaupt möglich ist.
Ansatz 3: zusätzliche Schnittstelle
Ein weiterer Lösungsansatz ist der Einsatz von Schnittstellen anstatt der Vererbung. Allerdings muss dieses direkt bei dem Design berücksichtigt werden.
Soll FB_SequenceManager so entworfen werden, dass der Anwender des Funktionsblocks beliebige Sortieralgorithmen hinzufügen kann, so sollte der Code für das Sortieren der Liste aus FB_SequenceManager entfernt werden. Der Zugriff aus dem Sortieralgorithmus auf die Liste sollte stattdessen über eine Schnittstelle erfolgen.
Bezogen auf unser Beispiel wird die Schnittstelle I_SequenceSortable hinzugefügt. Diese Schnittstelle enthält die Methode SortList(), welche eine Referenz auf die zu sortierende Liste enthält.
METHOD SortList
VAR_INPUT
refSequence : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR
Als nächstes werden die Funktionsblöcke angelegt, in denen die jeweiligen Sortieralgorithmen hinterlegt sind. Jeder dieser Funktionsblöcke implementiert die Schnittstelle I_SequenceSortable. Als Beispiel wird hier der Funktionsblock gezeigt, der nach nId aufsteigend sortiert.
FUNCTION_BLOCK PUBLIC FB_SequenceSortedByIdAscending IMPLEMENTS I_SequenceSortable
Der Name des Funktionsblocks ist beliebig, entscheidend ist die Implementierung der Schnittstelle I_SequenceSortable. Dadurch ist sichergestellt das FB_SequenceSortedByIdAscending die Methode SortList() enthält. In der Methode SortList() wird der eigentliche Sortieralgorithmus implementiert.
METHOD SortList
VAR_INPUT
refSequence : REFERENCE TO ARRAY [1..5] OF ST_SequenceItem;
END_VAR
// Sort the list by nId in ascending order
// …
FB_SequenceManager erhält in der Methode Sort() einen Parameter vom Typ I_SequenceSortable. Wird die Methode Sort() aufgerufen, so wird ein Funktionsblock (z.B. FB_SequenceSortedByIdAscending) übergeben, welcher die Schnittstelle I_SequenceSortable implementiert und somit auch die Methode SortList() enthält. In der Methode Sort() von FB_SequenceManager wird SortList() aufgerufen und eine Referenz der Liste aSequence übergeben.
METHOD PUBLIC Sort
VAR_INPUT
ipSequenceSortable : I_SequenceSortable;
END_VAR
IF (ipSequenceSortable <> 0) THEN
ipSequenceSortable.SortList(THIS^._aSequence);
END_IF
Dadurch erhält der Funktionsblock mit dem implementierten Sortieralgorithmus die Referenz auf die zu sortierende Liste.
Für jeden gewünschten Sortieralgorithmus wird ein Funktionsblock erstellt. Somit stehen uns zum einen FB_SequenceManager mit der Methode Sort() zur Verfügung und zum anderen die Funktionsblöcke, welche die Schnittstelle I_SequenceSortable implementieren und die Sortieralgorithmen enthalten.
Wird von FB_SequenceManager die Methode Sort() aufgerufen, so wird ein Funktionsblock übergeben (hier FB_SequenceSortedByIdAscending). Dieser Funktionsblock enthält die Schnittstelle I_SequenceSortable über die anschließend die Methode SortList() aufgerufen wird.
PROGRAM MAIN
VAR
fbSequenceManager : FB_SequenceManager;
fbSequenceSortedByIdAscending : FB_SequenceSortedByIdAscending;
// …
END_VAR
fbSequenceManager.Sort(fbSequenceSortedByIdAscending);
// …
Bei diesem Ansatz wird keine Vererbung angewendet. Die Funktionsblöcke für die Sortieralgorithmen könnten ihre eigene Vererbungshierarchie anwenden, falls dieses gefordert wird. Ebenfalls könnten die Funktionsblöcke weitere Schnittstellen implementieren, da das Implementieren mehrerer Schnittstellen möglich ist.
Datenhaltung (Liste) und Datenverarbeitung (Sortierung) sind durch den Einsatz der Schnittstelle klar voneinander getrennt. Die Eigenschaft aSequence benötigt keinen Schreibzugriff. Auch sind Zugriffe auf interne Variablen von FB_SequenceManager nicht notwendig.
Auch die beiden Datentypen E_SortedOrder und E_SortedDirection werden nicht benötigt. Die Auswahl der Sortierung wird ausschließlich durch den Funktionsblock bestimmt, der an Sort() übergeben wird.
Wird eine neue Sortierung hinzugefügt, so ist es nicht notwendig schon vorhandene Elemente zu verändern oder anzupassen.
Beispiel 4 (TwinCAT 3.1.4024) auf GitHub
Analyse der Optimierung
Es gibt verschiedene Techniken, um einen bestehenden Funktionsblock funktional zu erweitern, ohne diesen verändern zu müssen. Neben der Vererbung, eine der Hauptmerkmale der objektorientierten Programmierung (OOP), stellen Schnittstellen evtl. eine bessere Alternative dar.
Bei der Verwendung von Schnittstellen ist die Entkopplung größer. Allerdings müssen beim Softwareentwurf die einzelnen Schnittstellen implementiert werden. Es muss also im Vorfeld überlegt werden, welche möglichen Bereiche durch Schnittstellen abstrahiert werden und welche nicht.
Aber auch bei Verwendung von Vererbung muss bei der Entwicklung eines Funktionsblocks überlegt werden, welche internen Elemente den abgeleiteten Funktionsblöcken per PROTECTED angeboten werden.
Die Definition des Open/Closed Principle
Das Open/Closed Principle (OCP) wurde im Jahr 1988 von Bertrand Meyer formuliert und besagt:
Eine Softwareentität sollte offen für Erweiterungen, aber zugleich auch geschlossen gegenüber Modifikationen sein.
Softwareentität: Damit ist eine Klasse, Funktionsblock, Module, Methode, Service, … gemeint.
Offen: Das Verhalten von Softwaremodule sollte erweiterbar sein.
Geschlossen: Eine Erweiterbarkeit soll nicht dadurch erreicht werden, indem bestehende Software verändert wird.
Als das Open/Closed Principle (OCP) von Bertrand Meyer Ende der 80er definiert wurde, lag der Fokus auf der Programmiersprache C++. Er nutzte die in der objektorientierten Welt bekannte Vererbung. Die damals noch junge Disziplin der Objektorientierung versprach große Verbesserungen bei Wiederverwendbarkeit und Wartbarkeit dadurch, dass konkrete Klassen als Basisklassen für neue Klassen verwendet werden können.
Als Robert C. Martin in den 90er Jahren das Prinzip von Bertrand Meyer übernahm, setzte er es technisch anders um. C++ ermöglicht die Verwendung von Mehrfachvererbung, während in neueren Programmiersprachen Mehrfachvererbung eher selten anzutreffen ist. Aus diesem Grund setzte Robert C. Martin den Fokus auf die Verwendung von Schnittstellen. Weitere Informationen hierzu sind in dem Buch (Amazon-Werbelink *) Clean Architecture: Das Praxis-Handbuch für professionelles Softwaredesign zu finden.
Zusammenfassung
Die Einhaltung des Open/Closed Principle (OCP) birgt allerdings die Gefahr des Overengineering. Die Möglichkeit für Erweiterungen sollte nur dort implementiert werden, wo sie konkret benötigt wird. Eine Software lässt sich nicht so designen, dass jede denkbare Erweiterung umgesetzt werden kann, ohne dass Anpassungen an dem Quellcode notwendig sind.
Damit ist meine Serie über die SOLID-Prinzipien abgeschlossen. Neben den SOLID-Prinzipien gibt es allerdings noch weitere Prinzipien, wie z.B. Keep It Simple, Stupid (KISS), Don’t Repeat Yourself (DRY), Law Of Demeter (LOD) oder You Ain‘t Gonna Need It (YAGNI). All diese Prinzipen haben das gemeinsame Ziel, die Wartbarkeit und die Wiederverwendbarkeit von Software zu verbessern.
What is Playwright?
Playwright is a Web UI testing framework that supports different languages and is maintained by Microsoft. Playwright can be used with JavaScript/TypeScript, Python, Java and for sure C#. It comes with windowless browser support with various browsers. It has to be used with unit testing frameworks and because of this, you can just run it within your CI/CD pipeline. The syntax is pretty intuitive and I actually love it. Besides that the documentation is really good and helps a lot to easily start working with it.
In this blog post, I don't want to introduce Playwright. Actually, the website and the documentation is a much better resource to learn about the it. I would like to play around with it and to use it differently. Instead of testing a pre-hosted web application, I'd like to test a web application that is self hosted in the test project using the WebApplicationFactory
. This way you have really isolated UI tests that don't relate to on another infrastructure and won't fail because of network problems.
Does it work?
Let's try it:
Setting up the solution
The following lines create an ASP.NET Core MVC project and an NUnit test project. After that, a solution file will be created and the projects will be added to the solution. The last command adds the NUnit implementation of Playwright to the test project:
dotnet new mvc -n PlayWithPlaywright
dotnet new nunit -n PlayWithPlaywright.Tests
dotnet new sln -n PLayWithPlaywright
dotnet sln add .\PlayWithPlaywright\
dotnet sln add .\PlayWithPlaywright.Tests\
dotnet add .\PlayWithPlaywright.Tests\ package Microsoft.Playwright.NUnit
Run those commands and build the solution:
dotnet build
The build is needed to copy a PowerShell script to the output directory of the test project. This PowerShell script is the command line interface to control playwright.
At next we need to install the required browsers to execute the tests via that PowerShell:
.\PlayWithPlaywright.Tests\bin\Debug\net7.0\playwright.ps1 install
Generating test code
Using the codegen
command helps you to autogenerate test code that can be copied to the test project:
.\PlayWithPlaywright.Tests\bin\Debug\net7.0\playwright.ps1 codegen https://asp.net-hacker.rocks/
This command opens the Playwright Inspector where you can record your test case. While clicking through your application the test code will be generated on the right hand side:

Instead of testing an external website like I did, you can also call codegen
with a locally running application.
Just copy the generated code into the NUnit test project and fix the namespace and class name to match the namespace of your project.
Using the generated code as an example you will be able to write more the tests manually.
If this is done, just run dotnet test
to execute the generated test and just to verify that Playwright is working.
Start playing
Usually Playwright is testing applications that are running somewhere on a server. This as one simple problem: If the test cannot connect to the running application because of network issues the test will fail. Usually a test should only have one single reason to fail: It should fail because the expected behavior didn't occure.
The solution would be to test a web application that is hosted on the same infrastructure and within the same process as the actual test.
Microsoft already provided the possibility to write integration tests against a web application using the WebApplicationFactory. My Idea was to use this WebApplicationFactory
to host an application that can be tested with Playwright.
Since the WebApplicationFactory also provides a HttpClient, I would expect to have an URL to connect to. That HttpClient would have a BaseAddress that I can use to pass to Playwright.
Would this really work?
WebApplicationFactory and Playwright
Actually, we can't combine them by default because the WebApplicationFactory
doesn't really host a web application over HTTP. That means it doesn't use Kestrel to expose an endpoint over HTTP. The WebApplicationFactory
creates a test server that hosts the application in memory and just simulates an actual HTTP server.
We need to find a way to start a HTTP server, like Kestrel, to host the application. Actually we could start WebApplicationBuilder
but the Idea was to reuse the configuration of the Program.cs of the application we want to test. Like it is done with the WebApplicationFactory
.
Daniel Donbavand actually found a solution how to override the WebApplicationFactory to actually host the application over HTTP and to get an endpoint that can be used with Playwright. I used Daniels solution but made it a little more Generic.
Let's see how this works together with Playwright.
First, add a project reference to the web project within the Playwright test project and add a package reference to Microsoft.AspNetCore.Mvc.Testing.
dotnet add .\PlayWithPlaywright.Tests\ reference .\PlayWithPlaywright\
dotnet add .\PlayWithPlaywright.Tests\ package Microsoft.AspNetCore.Mvc.Testing
The first one is needed to use the Program.cs
with the WebApplicationFactory
. The second one adds the WebApplicationFactory
and the test server to the test project.
To use the Program
class that is defined in a Program.cs
that uses the minimal API you can simply add an empty partial Program class to the Program.cs
.
I just put the following line at the end of the Program.cs
:
public partial class Program { }
To make the Playwright tests as generic as possible I created an abstract SelfHostedPageTest
class that inherits the PageTest
class that comes with Playwright and use the CustomWebApplicationFactory
there and just expose the server address to the test class that inherits the SelfHostedPageTest
:
public abstract class SelfHostedPageTest<TEntryPoint> : PageTest where TEntryPoint : class
{
private readonly CustomWebApplicationFactory<TEntryPoint> _webApplicationFactory;
public SelfHostedPageTest(Action<IServiceCollection> configureServices)
{
_webApplicationFactory = new CustomWebApplicationFactory<TEntryPoint>(configureServices);
}
protected string GetServerAddress() => _webApplicationFactory.ServerAddress;
}
The actual Playwright test just inherits the SelfHostedPageTest
as follows instead of the PageTest
:
public class PlayWithPlaywrightHomeTests : SelfHostedPageTest<Program>
{
public PlayWithPlaywrightHomeTests() :
base(services =>
{
// configure needed services, like mocked db access, fake mail service, etc.
}) { }
// ...
}
As you can see, I pass in the Program type as generic argument to the SelfHostedPageTest
. The CustomWebApplicationFactory
that is used inside is almost the same implementation as done by Daniel. I just added the generic argument for the Program class and added the possibility to pass the service configuration via the constructor:
internal class CustomWebApplicationFactory<TEntryPoint> :
WebApplicationFactory<TEntryPoint> where TEntryPoint : class
{
private readonly Action<IServiceCollection> _configureServices;
private readonly string _environment;
public CustomWebApplicationFactory(
Action<IServiceCollection> configureServices,
string environment = "Development")
{
_configureServices = configureServices;
_environment = environment;
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment(_environment);
base.ConfigureWebHost(builder);
// Add mock/test services to the builder here
if(_configureServices is not null)
{
builder.ConfigureServices(_configureServices);
}
}
// ...
}
Now we can use GetServerAddress()
to get the server address and to pass it to the Page.GotoAsync()
method:
[Test]
public async Task TestWithWebApplicationFactory()
{
var serverAddress = GetServerAddress();
await Page.GotoAsync(serverAddress);
await Expect(Page).ToHaveTitleAsync(new Regex("Home Page - PlayWithPlaywright"));
Assert.Pass();
}
That's it.
To try it out. just call dotnet test on the Command Line or PowerShell or run the relevant test in a test explorer.
Conclusion
The result with my test project looks like the following while running all the tests when I was offline:

One failing test is the recorded test session of my blog on https://asp.net-hacker.rocks/ and the other one is the demo test I found on https://playwright.dev. The passed test is the one that uses the CustomWebApplicationFactory
This is exactly the result I expected.
You'll find the the example on my GitHub repository.
Die jüngste Version von Microsofts Programmiersprache belegt in parameterlosen Konstruktoren die Felder und Properties von Strukturen mit Standardwerten.
The basic idea of the Interface Segregation Principle (ISP) has strong similarities with the Single Responsibility Principle (SRP): Modules with too many responsibilities can negatively influence the maintenance and maintainability of a software system. The Interface Segregation Principle (ISP) focuses on the module’s interface. A module should implement only those interfaces that are needed for its task. The following shows how this design principle can be implemented.
Starting situation
In the last post (IEC 61131-3: SOLID – The Liskov Substitution Principle), the example was extended by another lamp type (FB_LampSetDirectDALI). The special feature of this lamp type is the scaling of the output value. While the other lamp types output 0-100%, the new lamp type outputs a value from 0 to 254.
Just like all other lamp types, the new lamp type (DALI lamp) has an adapter (FB_LampSetDirectDALIAdapter). The adapters have been added during the implementation of the Single Responsibility Principle (SRP) and ensure that the function blocks of the individual lamp types are only responsible for a single function (see IEC 61131-3: SOLID – The Single Responsibility Principle).
The sample program was last adapted so that the output value from the new lamp type (FB_LampSetDirectDALI) is scaled within the adapter from 0-254 to 0-100 %. This makes the DALI lamp behave exactly like the other lamp types without violating the Liskov Substitution Principle (LSP).
This will serve as a starting point for explaining the Interface Segregation Principle (ISP).
Extension of the implementation
Also this time, the application has to be extended. However, it is not a new lamp type that is defined, but an existing lamp type is extended by a functionality. The DALI lamp should be able to count the operating hours. For this purpose, the function block FB_LampSetDirectDALI is extended by the property nOperatingTime.
PROPERTY PUBLIC nOperatingTime : DINT
The setter can be used to set the operating hours counter to any value, while the getter returns the current state of the operating hours counter.
Since FB_Controller represents the individual lamp types, this function block is also extended by nOperatingTime.
The operating hours are recorded in the FB_LampSetDirectDALI function block. If the output value is > 0, the operating hours counter is incremented by 1 every second:
IF (nLightLevel > 0) THEN
tonDelay(IN := TRUE, PT := T#1S);
IF (tonDelay.Q) THEN
tonDelay(IN := FALSE);
_nOperatingTime := _nOperatingTime + 1;
END_IF
ELSE
tonDelay(IN := FALSE);
END_IF
The variable _nOperatingTime is the backing variable for the new property nOperatingTime and is declared in the function block.
What possibilities are there to transfer the value of nOperatingTime from FB_LampSetDirectDALI to the property nOperatingTime of FB_Controller? Here, too, there are now various approaches of integrating the required extension into the given software structure.
Approach 1: Extension of I_Lamp
The property for the new feature is integrated into the I_Lamp interface. Thus, the abstract function block FB_Lamp also receives the nOperatingTime property. Since all adapters inherit from FB_Lamp, the adapters of all lamp types receive this property, regardless of whether the lamp type supports an operating hours counter or not.
The getter and the setter of nOperatingTime in FB_Controller can thus directly access nOperatingTime of the individual adapters of the lamp types. The getter of FB_Lamp (abstract function block from which all adapters inherit) returns the value -1. The absence of the operating hours counter can thus be detected.
IF (fbController.nOperatingTime >= 0) THEN
nOperatingTime := fbController.nOperatingTime;
ELSE
// service not supported
END_IF
Since FB_LampSetDirectDALI supports the operating hours counter, the adapter (FB_LampSetDirectDALIAdapter) overwrites the nOperatingTime property. The getter and the setter from the adapter access nOperatingTime from FB_LampSetDirectDALI. In this way, the value of the operating hours counter is passed on to FB_Controller.
(abstract elements are displayed in italics)
Sample 1 (TwinCAT 3.1.4024) on GitHub
This approach implements the feature as desired. Also, none of the SOLID principles shown so far are violated.
However, the central interface I_Lamp is extended only to add another feature for one lamp type. All other adapters of the lamp types, even those that do not support the new feature, also receive the nOperatingTime property via the abstract base FB_Lamp.
With each feature that is added in this way, the interface I_Lamp increases and so does the abstract base FB_Lamp.
Approach 2: Additional Interface
In this approach, the I_Lamp interface is not extended, but a new interface (I_OperatingTime) is added for the desired functionality. I_OperatingTime contains only the property necessary for providing the operating hours counter:
PROPERTY PUBLIC nOperatingTime : DINT
This interface is implemented by the adapter FB_LampSetDirectDALIAdapter.
FUNCTION_BLOCK PUBLIC FB_LampSetDirectDALIAdapter EXTENDS FB_Lamp IMPLEMENTS I_OperatingTime
Thus, FB_LampSetDirectDALIAdapter receives the property nOperationTime not via FB_Lamp or I_Lamp, but via the new interface I_OperatingTime.
If FB_Controller accesses the active lamp type in the getter of nOperationTime, it is checked before the access whether the selected lamp type implements the I_OperatingTime interface. If this is the case, the property is accessed via I_OperatingTime. If the lamp type does not implement the interface, -1 is returned.
VAR
ipOperatingTime : I_OperatingTime;
END_VAR
IF (__ISVALIDREF(_refActiveLamp)) THEN
IF (__QUERYINTERFACE(_refActiveLamp, ipOperatingTime)) THEN
nOperatingTime := ipOperatingTime.nOperatingTime;
ELSE
nOperatingTime := -1; // service not supported
END_IF
END_IF
The setter of nOperationTime is structured similarly. After the successful check whether I_OperatingTime is implemented by the active lamp, the property is accessed via the interface.
VAR
ipOperatingTime : I_OperatingTime;
END_VAR
IF (__ISVALIDREF(_refActiveLamp)) THEN
IF (__QUERYINTERFACE(_refActiveLamp, ipOperatingTime)) THEN
ipOperatingTime.nOperatingTime := nOperatingTime;
END_IF
END_IF
(abstract elements are displayed in italics)
Sample 2 (TwinCAT 3.1.4024) on GitHub
Optimization analysis
The use of a separate interface for the additional feature corresponds to the ‘optionality’ from IEC 61131-3: SOLID – The Liskov Substitution Principle. In the above example, it can be checked at runtime of the program (with __QUERYINTERFACE()) whether a specific interface is implemented and thus the respective feature is supported. Further features, like bIsDALIDevice from the ‘Optionality’ example, are not necessary with this solution approach.
If a separate interface is offered for each feature or functionality, other lamp types can also implement this in order to implement the desired feature. If FB_LampSetDirect also has to receive an operating hours counter, FB_LampSetDirect must be extended by the property nOperatingTime. In addition, FB_LampSetDirectAdapter must implement the I_OperatingTime interface. All other function blocks, including FB_Controller, remain unchanged.
If the functionality of the operating hours counter changes and I_OperatingTime receives additional methods, only the function blocks that also support the feature must be adapted.
Examples of the Interface Segregation Principle (ISP) can also be found in .NET. For example, .NET has the interface IList. This interface contains methods and properties for creating, modifying and reading listings. However, depending on the use case, it may be sufficient for the user to only read a listing. However, passing a listing through IList in this case would also provide methods to modify the listing. One can use the IReadOnlyList interface for these use cases. With this interface, a listing can only be read. Accidental modification of the data is therefore not possible.
Dividing functionalities into individual interfaces thus increases not only the maintainability but also the security of a software system.
The definition of the Interface Segregation Principle
This brings us to the definition of the Interface Segregation Principle (ISP):
A module that uses an interface should be presented with only those methods that the interface really needs.
Or to put it another way:
Clients should not be forced to depend on methods they do not need.
A common argument against the Interface Segregation Principle (ISP) is the increased number of interfaces. A software design can still be adapted at any time during its development cycles. So, if you feel that an interface contains too many functionalities, check whether segregation is possible. Of course, overengineering should always be avoided. A certain amount of experience can be helpful here.
Abstract function blocks also represent an interface (see FB_Lamp). An abstract function block can contain basic functions to which the user only adds the necessary details. It is not necessary to implement all the methods or properties yourself. Here also it is important not to burden the user with technicalities which are not necessary for his tasks. The set of abstract methods and properties should be as small as possible.
Adherence to the Interface Segregation Principle (ISP) keeps interfaces between functional blocks as small as possible, reducing coupling between each functional block.
Summary
If a software system has to cover further performance features, reflect the new requirements and do not hastily extend existing interfaces. Check whether separate interfaces are not a better decision. The reward is a software system that is easier to maintain, to test and to extend.
In the last pending part, the Open/Closed Principle (OCP) will be explained in more detail.
Ein neues Schlüsselwort für Microsofts Programmiersprache C# legt fest, dass Properties oder Felder zwingend gesetzt werden müssen.
UI testing is an essential part of mobile app development to ensure that the app delivers the best possible user experience and meets the needs and expectations of its users. But how do we do that in .NET MAUI when Xamarin.UITest is not fully compatible anymore? Let's look at 3 alternatives to Xamarin.UITest.
Das Pattern Matching funktioniert in C# 11 mit Listen. Außerdem lassen sich Teilmengen extrahieren.
Azure DevOps Server 2022 - OnPrem?
Yes I know - you can get everything from the cloud nowadays, but we are still using our OnPrem hardware and were running the “old” Azure DevOps Server 2020.
The _Azure DevOps Server 2022 was released last december, so an update was due.
Requirements
If you are running am Azure DevOps Server 2020 the requirements for the new 2022 release are “more or less” the same except the following important parts:
- Supported server operation systems: Windows Server 2022 & Windows Server 2019 vs. the old Azure DevOps Server 2020 could run under a Windows Server 2016
- Supported SQL Server versions: Azure SQL Database, SQL Managed Instance, SQL Server 2019, SQL Server 2017 vs. the old Azure DevOps Server supported SQL Server 2016.
Make sure you have a backup
The last requirement was a suprise for me, because I thought the update should run smoothly, but the installer removed the previous version and I couldn’t update, because our SQL Server was still on SQL Server 2016. Fortunately we had a VM backup and could rollback to the previous version.
Step for Step
The update process itself was straightforward: Download the installer and run it.










The screenshots are from two different sessions. If you look carefully on the clock you might see that the date is different, that is because of the SQL Server 2016 problem.
As you can see - everything worked as expected, but after we updated the server the search, which is powered by ElasticSearch was not working. The “ElasticSearch”-Windows-Service just crashed on startup and I’m not a Java guy, so… we fixed it by removing the search feature and reinstall it.
We tried to clean the cache, but it was still not working. After the reinstall of this feature the issue went away.
Features
Azure Server 2022 is just a minor update (at least from a typical user perspective). The biggest new feature might be “Delivery Plans”, which are nice, but for small teams not a huge benefit. Check out the release notes.
A nice - nerdy - enhancement, and not mentioned in the release notes: “mermaid.js” is now supported in the Azure DevOps Wiki, yay!
Hope this helps!
Finally! After months of not writing a blog post, here it is:
A GitHub Issue on the ASP.NET Core Docs points me to Polly CircuitBreaker. Which is really great. Before that, I didn't even know that circuit breakers is a term in the software industry. Actually, I implemented mechanisms that work like that but never called them circuit breakers. Maybe that's the curse of never having visited a university :-D
http://www.thepollyproject.org/
What is a circuit breaker?
Let's assume you have a connection to an external resource that breaks from time to time, which doesn't break your application but degraded the health of your application. In case you check that broken connection your application will be in a degraded state from time to time. What if those connection issues increase? When will it be a broken state? One broken connection out of one thousand might be okay. One out of ten might look quite unhealthy, right? If so, it makes sense to count the number of issues within a period of time and throw an exception if the number of exceptions exceeds the allowed number of exceptions. Exactly this is a circuit breaker.
Please excuse the amateurish explanation, I'm sure Martin Fowler can do it much better.
With Polly's circuit breaker, you can define how many specific exceptions are allowed to happen within a specific time period before throwing an exception.
The following snippet shows the usage of Polly's circuit breaker:
var policy = Policy.Handle<HttpRequestException>()
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 2,
durationOfBreak: TimeSpan.FromMinutes(1)
));
await policy.ExecuteAsync(async () =>
{
var client = new HttpClient();
var response = await client.GetAsync("http://localhost:5259/api/dummy");
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException();
}
});
This creates an AsyncCircuitBreakerPoliy
that allows two exceptions within a minute before throwing an exception.
Actually, I wanted to see how this would look like in an ASP.NET Core Health Check. The health check I'm going to show here isn't perfect but shows the concept of it:
Creating a circuit breaker health check
Adding a circuit breaker to a health check or in general into a web application requires you to persist the state of that circuit breaker over multiple scopes or requests. This means we need to store instances of the AsyncCircuitBreakerPolicy
as singletons in the service collection. See here.
Preparing the test application
To test the implementation I created a minimal endpoint that fails randomly within a new web application:
app.MapGet("/api/dummy", () =>
{
var rnd = Random.Shared.NextInt64(0, 1000);
if ((rnd % 5) == 0)
{
throw new Exception("new exception");
}
return rnd;
});
This endpoint returns a random number and fails in case the random number can be divided by five. This exception is meaningless, but the endpoint is good to test the health check we will implement.
We also need to create a health check endpoint that we will call to see the current health state. This endpoint also executes the health check every time we call it. When calling it, the health check will call the dummy API and gets a randomly generated error.
app.UseHealthChecks("/health");
Implementing the health check
Next, we are going to write a health check that gets an AsyncCircuitBreakerPolicy
via the service provider and executes a web request against the dummy breaking endpoint:
using Microsoft.Extensions.Diagnostics.HealthChecks;
namespace CircuitBreakerChecks;
public class ApiCircuitBreakerHealthCheck<TPolicy> : IHealthCheck where TPolicy : ApiCircuitBreakerContainer
{
private readonly ApiCircuitBreakerHealthCheckConfig _config;
private readonly IServiceProvider _services;
public ApiCircuitBreakerHealthCheck(
ApiCircuitBreakerHealthCheckConfig config,
IServiceProvider services)
{
_config = config;
_services = services;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
var policy = _services.GetService<TPolicy>()?.Policy;
try
{
if (policy is not null)
{
await policy.ExecuteAsync(async () =>
{
var client = new HttpClient();
var response = await client.GetAsync(_config.Url);
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException();
}
});
}
}
catch (Exception)
{
return HealthCheckResult.Unhealthy("Unhealthy");
}
return HealthCheckResult.Healthy("Healthy");
}
}
This health check is generic and receives a container for the AsyncCircuitBreakerPolicy
as a generic type argument. We'll see later why.
In the CheckHealthMethod
we take the specific container from the service provider to get the actual Polly AsyncCircuitBreakerPolicy
and we use it as shown in the first snippet. That part was quite common.
The container is a really simple object that just stores the Policy:
using Polly.CircuitBreaker;
namespace CircuitBreakerChecks;
public class ApiCircuitBreakerContainer
{
private readonly AsyncCircuitBreakerPolicy _policy;
public ApiCircuitBreakerContainer(AsyncCircuitBreakerPolicy policy)
{
_policy = policy;
}
public AsyncCircuitBreakerPolicy Policy => _policy;
}
This container gets registered as a singleton to persist the policy for a longer period of time.
The health check also uses a configuration class that passes the configuration arguments to the health check. Currently, it is just the URL of the API to test and the name of the health check registration:
namespace CircuitBreakerChecks;
public class ApiCircuitBreakerHealthCheckConfig
{
public string Url { get; set; }
}
This configuration class gets registered as transient.
Now let's puzzle that all together to get it running. We could do that all in the Program.cs
, but will mess up the file, though.
Instead of messing up the Program.cs
, I would like to have a configuration like this:
builder.Services.AddApiCircuitBreakerHealthCheck(
"http://localhost:5259/api/dummy", // URL to check
"AddApiCircuitBreakerHealthCheck", // Name of the health check registration
Policy.Handle<HttpRequestException>() // Polly CircuitBreaker Async Policy
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 2,
durationOfBreak: TimeSpan.FromMinutes(1)
));
In your project, you might need to change the URL to match your local port.
The call in this snippet will register and configure the ApiCircuitBreakerHealthCheck
. This means we will create an extension method on the IServiceCollection
to stick that all together:
using Polly.CircuitBreaker;
namespace CircuitBreakerChecks;
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddApiCircuitBreakerHealthCheck(
this IServiceCollection services,
string url,
string name,
AsyncCircuitBreakerPolicy policy)
{
services.AddTransient(_ => new ApiCircuitBreakerHealthCheckConfig { Url = url });
services.AddSingleton(new ApiCircuitBreakerContainer(policy));
services.AddHealthChecks()
.AddCheck<ApiCircuitBreakerHealthCheck<ApiCircuitBreakerContainer>>(name);
return services;
}
}
That's it.
Trying it out
To try it out, run the application and call the health check endpoint in the browser.
The first two calls should display a healthy state for sure. Then it stays healthy until it gets at least two errors within a period of one minute. After that, it stays unhealthy until it gets less than two errors within that period.
Play around with it. Debug the minimal endpoint or debug the health check. It is kind of fun.
I published the demo code to GitHub: https://github.com/JuergenGutsch/aspnetcore-circuitbreaker-healthcheck
One issue left
With this implementation, we can just use one registration of this endpoint. Creating a generic health check that way didn't really make sense. The reason is the singleton instance of the Policy CircuitBreaker. This instance would be shared over multiple health check registrations. To solve this we need to find a way to register a unique singleton of a policy per health check registration. But this is a different story.
The CRA Problem
In my previous post I showed a simple setup with ASP.NET Core & React. The React part was created with the “CRA”-Tooling, which is kind of problematic. The “new” state of the art React tooling seems to be vite.js - so let’s take a look how to use this.

Step for Step
Step 1: Create a “normal” ASP.NET Core project
(I like the ASP.NET Core MVC template, but feel free to use something else - same as in the other blogpost)

Step 2: Install vite.js and init the template
Now move to the root directory of your project with a shell and execute this:
npm create vite@latest clientapp -- --template react-ts
This will install the latest & greatest vitejs based react app in a folder called clientapp
with the react-ts
template (React with Typescript). Vite itself isn’t focused on React and supports many different frontend frameworks.

Step 3: Enable HTTPS in your vite.js
Just like in the “CRA”-setup we need to make sure, that the environment is served under HTTPS. In the “CRA” world we needed to different files from the original ASP.NET Core & React template, but with vite.js there is a much simpler option available.
Execute the following command in the clientapp
directory:
npm install --save-dev vite-plugin-mkcert
Then in your vite.config.ts
use this config:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import mkcert from 'vite-plugin-mkcert'
// https://vitejs.dev/config/
export default defineConfig({
base: '/app',
server: {
https: true,
port: 6363
},
plugins: [react(), mkcert()],
})
Be aware: The base: '/app'
will be used as a sub-path.
The important part for the HTTPS setting is that we use the mkcert()
plugin and configure the server part with a port and set https
to true
.
Step 4: Add the Microsoft.AspNetCore.SpaServices.Extensions NuGet package
Same as in the other blogpost, we need to add the Microsoft.AspNetCore.SpaServices.Extensions NuGet package to glue the ASP.NET Core development and React world together. If you use .NET 7, then use the version 7.x.x, if you use .NET 6, use the version 6.x.x - etc.

Step 5: Enhance your Program.cs
Back to the Program.cs
- this is more or less the same as with the “CRA” setup:
Add the SpaStaticFiles
to the services collection like this in your Program.cs
- be aware, that vite.js builds everything in a folder called dist
:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// ↓ Add the following lines: ↓
builder.Services.AddSpaStaticFiles(configuration => {
configuration.RootPath = "clientapp/dist";
});
// ↑ these lines ↑
var app = builder.Build();
Now we need to use the SpaServices like this:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// ↓ Add the following lines: ↓
var spaPath = "/app";
if (app.Environment.IsDevelopment())
{
app.MapWhen(y => y.Request.Path.StartsWithSegments(spaPath), client =>
{
client.UseSpa(spa =>
{
spa.UseProxyToSpaDevelopmentServer("https://localhost:6363");
});
});
}
else
{
app.Map(new PathString(spaPath), client =>
{
client.UseSpaStaticFiles();
client.UseSpa(spa => {
spa.Options.SourcePath = "clientapp";
// adds no-store header to index page to prevent deployment issues (prevent linking to old .js files)
// .js and other static resources are still cached by the browser
spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ResponseHeaders headers = ctx.Context.Response.GetTypedHeaders();
headers.CacheControl = new CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MustRevalidate = true
};
}
};
});
});
}
// ↑ these lines ↑
app.Run();
Just like in the original blogpost. In the development mode we use the UseProxyToSpaDevelopmentServer
-method to proxy all requests to the vite.js dev server. In the real world, we will use the files from the dist
folder.
Step 6: Invoke npm run build during publish
The last step is to complete the setup. We want to build the ASP.NET Core app and the React app, when we use dotnet publish
:
Add this to your .csproj
-file and it should work:
<PropertyGroup>
<SpaRoot>clientapp\</SpaRoot>
</PropertyGroup>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)dist\**" /> <!-- Changed to dist! -->
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath> <!-- Changed! -->
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
Result
You should now be able to use Visual Studio Code (or something like this) and start the frontend project with dev
. If you open a browser and go to https://127.0.0.1:6363/app
you should see something like this:

Now start the ASP.NET Core app and go to /app
and it should look like this:

Ok - this looks broken, right? Well - this is a more or less a “known” problem, but can be easily avoided. If we import the logo from the assets it works as expected and shouldn’t be a general problem:

Code
The sample code can be found here.
Video
I made a video about this topic (in German, sorry :-/) as well - feel free to subscribe ;)
Hope this helps!
Das aktuelle Release von Microsofts Programmiersprache C# führt mit file einen neuen Scope für Klassen, Strukturen, Interfaces und Co ein.
How you can unlock the popular free TV channels of ORF and ServusTV with a VPN for Austria. With a VPN like the one from CyberGhost* you can unlock sports events like Formula 1, matches of the UEFA Champions League, the UEFA Europa League, the World Cup and European Championship, DFB-Pokal, as well as a lot of winter sports.
How can you enjoy the free content of ORF and ServusTV, without having to be in Austria? I’ll show you here.
With a reliable VPN, such as our test winner CyberGhost, you can virtually transfer to Austria. Here is the explanation in detail:
How to unlock ORF and ServusTV Austria with VPN
Time needed: 15 minutes.
Unblock ORF and ServusTV in four simple steps with a VPN for Austria.
- Choose a VPN provider
Play it safe if you care about your data and choose a reputable provider like CyberGhost*. It has proven itself to me.
- Install and launch the VPN software
NordVPN and CyberGhost offer clients for Android, Windows, iOS, macOS, Amazon FireTV Stick, Linux and even Raspberry Pi. Install the right software for your system.
- Choose a server
Choose a server from Austria and connect. With our favorites, you have several servers at your disposal, which means you always have fallback options. This is important, because streaming providers sometimes uncover and block servers. In this case, only a change of server will help.
- Start streaming
Now you can watch ORF or ServusTV Austria completely protected from anywhere in the world. Once you are connected to the server, you can go to the ORF or ServusTV website and start streaming.
CyberGhost is our top choice – unblock ServusTV and ORF Austria
To access ORF and ServusTV from any location around the globe, you’ll need to navigate past the providers’ geoblocking. The most effective way to accomplish this is with a reliable and reputable VPN service. In my view, CyberGhost stands out as the premier VPN provider, making it the optimal choice for streaming ORF and ServusTV Austria worldwide. Of course, alternative providers are also an option. For CyberGhost, I am more than happy to pay around 3 Euros per month considering the array of benefits it provides. The stringent no-logs policy is worth the cost in itself. This guarantees that my data is never gathered, stored, or distributed. Thus, my ISP or the government will never be able to access my personal data.
The best 3 VPNs for Austria under the magnifying glass
Since choosing the right VPN service can become a doctoral thesis due to the unmanageable oversupply, we have listed the most important criteria. After all, not every VPN is suitable for the Austrian programs of ORF and ServusTV. The provider must be able to reliably and seamlessly bypass geo-blocking without being exposed and deliver the required data speed so that even sports events can be streamed optimally.
In my opinion, these 3 are the best VPN services for Austria:
The all-rounder CyberGhost – in detail
CyberGhost* offers the best price-performance ratio. It has client applications for Android, Windows, iOS, macOS, Amazon FireTV Stick, Linux, and even for Raspberry Pi. Simultaneous connection on up to 7 devices is possible. It also includes a kill switch feature. You can choose from an impressive total of over 100 servers located in Austria. The best part is, it offers a money-back guarantee – during this period, if you find the service not up to your liking, you can ask for your money back via CyberGhost Support.
The top streaming ExpressVPN – in detail
On the list of top VPN services, it’s impossible not to mention ExpressVPN*. Known for its high-speed performance and consistent reliability, ExpressVPN is a solid choice for VPN users across the globe. Its network spans 94 countries, providing a massive selection of servers to choose from. ExpressVPN caters to a wide range of devices, including Android, iOS, Windows, macOS, Linux, and even routers, with the ability to connect up to 5 devices simultaneously. A standout feature is its proprietary Lightway protocol, designed to deliver lightning-fast and ultra-secure connections. The company also stands behind a strict No-Logs policy, ensuring user data is never stored or shared. An additional benefit is the 24/7 customer support – a testament to their commitment to user satisfaction. Lastly, much like CyberGhost, ExpressVPN also offers a money-back guarantee, providing users with the confidence to try out the service risk-free.
PIA the VPN classic for Austria – in detail
With the VPN from PIA*, 10 parallel connections are possible. It offers a client for Windows, iOS, macOS, and Android. It has browser extensions with which you can unlock Austrian programs as well. PIA also offers a money-back guarantee.
FAQ – Frequently asked questions and answers about VPN usage for Austria
What to do if the streaming via VPN Austria does not work properly or not at all? Check your VPN connection. If you are sure that your VPN is switched on, delete the cache and cookies of the browser. Change the server manually and not via the automatic quick selection. If that doesn’t help, use the VPN of the popular providers via a browser extension on Chrome, Firefox and Safari. If it still doesn’t work, contact customer service, which is available 24/7 with reputable providers.
Why shouldn’t I stream ServusTV and ORF with a free VPN service? The free VPN services are mostly throttled versions of the renowned providers. The inadequate server selection in Austria can prevent you from being able to unblock ORF and ServusTV. Lack of data volume and data speed can be more than a nuisance when it comes to the streaming experience, especially for sports events.
How can I watch ORF TVthek from abroad? With a VPN, the geoblocking of ORF TVthek can also be unlocked.
Is VPN usage legal? Using a VPN is completely legal in Germany, but also in many other countries like Switzerland or Austria. Using a VPN for illegal actions, such as downloading copyrighted media, are of course not legal.
Which sports events can I stream for free through VPN Austria? Formula 1, UEFA Champions League matches, UEFA Europa League matches, World Cup and European Championship football matches, Ice Hockey World Championship matches and many more winter sports.
The post VPN Austria – Unlock ORF and ServusTV appeared first on xplatform.rocks.
Die neue Version von Microsofts Programmiersprache kann aus Zeichenketten-Literalen Bytefolgen in UTF-8-Codes erstellen.
The ASP.NET Core React template

Visual Studio (at least VS 2019 and the newer 2022) ships with a ASP.NET Core React template, which is “ok-ish”, but has some really bad problems:
The React part of this template is scaffolded via “CRA” (which seems to be problematic as well, but is not the point of this post) and uses JavaScript instead of TypeScript.
Another huge pain point (from my perspective) is that the template uses some special configurations to just host the react part for users - if you want to mix in some “MVC”/”Razor” stuff, you need to change some of this “magic”.
The good parts:
Both worlds can live together: During development time the ASP.NET Core stuff is hosted via Kestrel and the React part is hosted under the WebPack Development server. The lovely hot reload is working as expected and is really powerful.
If you are doing a release build, the project will take care of the npm-magic.
But because of the “bad problems” outweight the benefits, we try to integrate a typical react app in a “normal” ASP.NET Core app.
Step for Step
Step 1: Create a “normal” ASP.NET Core project
(I like the ASP.NET Core MVC template, but feel free to use something else)

Step 2: Create a react app inside the ASP.NET Core project
(For this blogpost I use the “Create React App”-approach, but you can use whatever you like)
Execute this in your ASP.NET Core template (node & npm must be installed!):
npx create-react-app clientapp --template typescript
Step 3: Copy some stuff from the React template
The react template ships with some scripts and settings that we want to preserve:

The aspnetcore-https.js
and aspnetcore-react.js
file is needed to setup the ASP.NET Core SSL dev certificate for the WebPack Dev Server.
You should also copy the .env
& .env.development
file in the root of your clientapp
-folder!
The .env
file only has this setting:
A more important setting is in the .env.development
file (change the port to something different!):
The port number 3333
and the https=true
will be important later, otherwise our setup will not work.
Also, add this line to the .env
-file (in theory you can use any name - for this sample we keep it spaApp
):
Step 4: Add the prestart to the package.json
In your project open the package.json
and add the prestart
-line like this:
"scripts": {
"prestart": "node aspnetcore-https && node aspnetcore-react",
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Step 5: Add the Microsoft.AspNetCore.SpaServices.Extensions NuGet package

We need the Microsoft.AspNetCore.SpaServices.Extensions NuGet-package. If you use .NET 7, then use the version 7.x.x, if you use .NET 6, use the version 6.x.x - etc.
Step 6: Enhance your Program.cs
Add the SpaStaticFiles
to the services collection like this in your Program.cs
:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// ↓ Add the following lines: ↓
builder.Services.AddSpaStaticFiles(configuration => {
configuration.RootPath = "clientapp/build";
});
// ↑ these lines ↑
var app = builder.Build();
Now we need to use the SpaServices like this:
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// ↓ Add the following lines: ↓
var spaPath = "/spaApp";
if (app.Environment.IsDevelopment())
{
app.MapWhen(y => y.Request.Path.StartsWithSegments(spaPath), client =>
{
client.UseSpa(spa =>
{
spa.UseProxyToSpaDevelopmentServer("https://localhost:3333");
});
});
}
else
{
app.Map(new PathString(spaPath), client =>
{
client.UseSpaStaticFiles();
client.UseSpa(spa => {
spa.Options.SourcePath = "clientapp";
// adds no-store header to index page to prevent deployment issues (prevent linking to old .js files)
// .js and other static resources are still cached by the browser
spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ResponseHeaders headers = ctx.Context.Response.GetTypedHeaders();
headers.CacheControl = new CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MustRevalidate = true
};
}
};
});
});
}
// ↑ these lines ↑
app.Run();
As you can see, we run in two different modes.
In our development world we just use the UseProxyToSpaDevelopmentServer
-method to proxy all requests that points to spaApp
to the React WebPack DevServer (or something else). The huge benefit is, that you can use the React ecosystem with all its tools. Normally we use Visual Studio Code to run our react frontend and use the ASP.NET Core app as the “Backend for frontend”.
In production we use the build artefacts of the react build and make sure, that it’s not cached. To make the deployment easier, we need to invoke npm run build
when we publish this ASP.NET Core app.
Step 7: Invoke npm run build during publish
Add this to your .csproj
-file and it should work:
<PropertyGroup>
<SpaRoot>clientapp\</SpaRoot>
</PropertyGroup>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>%(DistFiles.Identity)</RelativePath> <!-- Changed! -->
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
Be aware that these instruction are copied from the original ASP.NET Core React template and are slightly modified, otherwise the path wouldn’t match.
Result
With this setup you can add any spa app that you would like to add to your “normal” ASP.NET Core project.
If everything works as expected you should be able to start the React app in Visual Studio Code like this:

Be aware of the https://localhost:3333/spaApp. The port and the name is important for our sample!
Start your hosting ASP.NET Core app in Visual Studio (or in any IDE that you like) and all requests that points to spaApp
use the WebPack DevServer in the background:

With this setup you can mix all client & server side styles as you like - mission succeeded and you can use any client setup (CRA, anything else) as you would like to.
Code
The code (but with slightly modified values (e.g. another port)) can be found here.
Be aware, that npm i
needs to be run first.
Video
I uploaded a video on my YouTube channel (in German) about this setup:
Hope this helps!
Die in geschweiften Klammern gefassten Zeichenketten-Interpolationsausdrücke dürfen neuerdings Kommentare und Zeilenumbrüche enthalten.
Lucifer is a fictional Netflix series based on the DC Comics character of the same name. The show follows Lucifer Morningstar, the Devil, as he abandons his throne in Hell for Los Angeles, where he starts his own nightclub called Lux. While in LA, Lucifer becomes involved with the LAPD and helps solve crimes.
The show is available to watch on Netflix in most countries. However, due to licensing restrictions, it is not available in some countries. If you are unable to watch Lucifer on Netflix in your country, you can use a VPN to bypass these restrictions.
A VPN is a service that allows you to connect to the internet via a server run by a third party. This server acts as a middleman between you and the websites you visit. By connecting to a VPN server in a different country, you can make it appear as if you are located in that country. This allows you to access websites that are blocked in your country.
There are many VPNs available, and each has its own benefits and drawbacks. Here are some of the most popular VPNs:
– NordVPN: NordVPN is one of the most popular VPNs available. It offers high speeds and strong security features, making it a good choice for streaming Lucifer.
– ExpressVPN: ExpressVPN is another popular VPN with high speeds and strong security features. It is also easy to use, making it a good choice for beginners.
– IPVanish: IPVanish is a good option for those who want a VPN with a large selection of servers. It also offers strong security features.
– PureVPN: PureVPN is a good choice for those who want a low-cost VPN with good security features.
How to Watch Using a VPN?
To watch Lucifer using a VPN, you will need to connect to a VPN server that is located in the United States. This will allow you to bypass geographic restrictions and watch the series.
What Are the Benefits of Using a VPN?
The benefits of using a VPN include:
– increased security and privacy
– bypass geographic restrictions
– unblock websites and content
– anonymous browsing.
Using a VPN is a great way to watch content if it is blocked in your country. It allows you to bypass restrictions and access content from anywhere in the world. Additionally, VPNs provide a level of security and privacy that is not available when using public Wi-Fi networks. So, if you are looking for a way to stream your favourite shows, a VPN is the best option available.
The first two seasons of Lucifer are available on Netflix US, but due to licensing agreements, the third season is not available until May 8th. However, there is a way to watch Lucifer Season 3 on Netflix US using a VPN.
To watch Lucifer Season 3 on Netflix US using ExpressVPN, follow these steps:
1. Sign up for a ExpressVPN account here.
2. Download the ExpressVPN app for your device.
3. Connect to a US server.
4. Open Netflix and start watching Lucifer!
The post Stream Lucifer Netflix Series with a VPN appeared first on xplatform.rocks.
Das mit dem jüngsten .NET-Release veröffentlichte C# 11 bietet eine neue, einfache Methode zum Anlegen von Zeichenketten mit Umbrüchen und Einrückungen.
With the end of support for Xamarin approaching, developers are busy migrating existing Xamarin Forms projects to .NET MAUI as its successor. So are we, of course. In this article, I'll show 7 steps we've always had to take during the transition to make your transition easier.
You want to watch the UEFA Champions League on free TV abroad? Then I’ll show you how it works with a good VPN like the one from NordVPN. Below are the foreign channels and streams that still broadcast the UEFA Champions League free and legally on free TV:
Watching Champions League free TV abroad is possible, but only with a good VPN
Every year the best soccer teams in Europe compete against each other to be crowned as Champions League winners. Of course, you’ll see the best clubs in the competition competing against each other. For example, Bayern Munich, Juventus Turin, Manchester United, Paris St. Germain, Manchester City, Real Madrid, Borussia Dortmund and FC Barcelona. Teams from England, Spain and Germany in particular regularly get very far in the tournament. It is always the most exciting soccer tournament of the year, where no soccer fan wants to miss the games of their stars.
Soccer has become a big business. If you want to watch top soccer as a soccer fan, you have to pay a lot of money for pay TV and stadium visits. That’s why I did a little research on where you can still watch UEFA Champions League abroad on free TV. With the free TV channels listed above, you can watch it legally and for free with a good VPN.
Guide: How to watch Champions League abroad for free
Time needed: 15 minutes.
Here’s a quick guide on how to watch Champions League matches on free TV abroad.
- Get a reliable VPN
First of all, you need to know which streaming provider you want to use. Choose from the list of free TV channels above. Before that, you should choose a reliable VPN with which you want to watch the Champions League. I advise you to use NordVPN or CyberGhost. I use both myself all the time and it works perfectly.
- Install the VPN on your devices and connect
Decide on which devices you want to watch Champions League on free TV abroad. Install the VPN on all your devices – whether Android, Windows, macOS, iOS or Linux.
- Connect to the VPN server
Once the VPN software is installed on your device, you can connect to your destination country. In the list, the VPN server_countries are in brackets after the free TV channels.
- Visit the streaming provider
Once you have dialed in to the right country, simply visit the streaming provider’s website.
Champions League abroad for free on free TV
In some countries, Champions League matches continue to be shown free of charge. ServusTV Austria (servustv.com), for example, shows certain matches on Wednesdays. Especially in the preliminary round, the channel focuses on teams from its own country, but also on those with Austrian players or coaches. However, the broadcasts are subject to geoblocking and you need an Austrian IP address. With a good VPN like NordVPN or CyberGhost, this is no problem. You can use it to unblock the channel.
However, Champions League free TV abroad is also possible via other broadcasters. RTL Luxembourg or Belgium also stream various games for free. However, you need an IP address in Luxembourg or Belgium.
Why is it so complicated?
OK, it’s actually not as complicated as it sounds. The software of the best VPN providers is very user-friendly and even technically less experienced people can cope with it.
The problem at this point is called geoblocking. The broadcasters and streaming providers in the individual countries only have the license to broadcast the respective Champions League game in a certain region.
However, based on your IP address, the streaming providers know in which country you are located. If you come from England, for example, and want to stream ServusTV Austria, the service will block you, stating that the desired broadcast cannot be transmitted for legal reasons.
If you are on vacation in Austria, Luxembourg, Belgium or another country with free Champions League broadcasts on free TVL, the situation is of course different. If you use the WLAN in your Airbnb, hotel or a SIM card from the corresponding country, you will also get a correct IP address and the broadcasters will not block you anyway.
However, if you are not in the corresponding country and connect to a server in Austria, for example, and then visit the website of the Austrian streaming provider, the provider thinks you are physically there. Now the regional block is lifted and you can stream Champions League on free TV.
What can I do if it does not work right away?
There are a few reasons why streaming does not work despite VPN and also a few solutions.
If you are using Android or iOS, the mobile apps of the respective streaming providers often work better than browsers.
With various streaming providers, some browsers have problems and in this case just try another internet browser. It can also help to delete cookies and cache or to use the incognito mode. In Firefox this is called private window.
It also happens that your server is unmasked. Disconnect and connect to another server. This has also helped me.
The best VPN services also provide browser extensions that act as a proxy. This often works better. Proxies aren’t as secure, but they are faster and when streaming you want speed.
The VPN protocol can also play a role. Change it if it doesn’t work at all. You can change it with the best services directly in the app with a few clicks.
The fact is, if you’re smart and look around a bit, you can watch a lot of interesting Champions League games for free – it’s very easy to save money here!
FAQ – Questions and answers about streaming
You still have some questions about the Champions League on free TV? Maybe you’ll find the right answers in this section.
Can I watch Champions League for free? Yes, this is possible, but not everywhere anymore. There are several foreign broadcasters that stream UEFA Champions League matches on free TV. At the beginning of the article I have put a list of the channels that I have found.
Is it legal to watch Champions League with a VPN for free? Many believe that it is not illegal to bypass geoblocking and watch Champions League on free TV via foreign countries. You are almost certainly violating the terms of use of the streaming providers. It’s best to find out for yourself how this is regulated in your location.
The post UEFA Champions League Free TV abroad appeared first on xplatform.rocks.
In Belgium, Luxembourg, Austria and Switzerland, Formula 1 on free TV is still possible. With a reliable VPN, you can access these channels from anywhere to stream Formula 1 abroad on free TV for free. NordVPN* is my favorite here, because with it the free F1 streaming always works for me.
These channels show Formula 1 on free TV:
You can watch Formula 1 for free – for example via ORF / ServusTV or SRF
Perhaps a few more important notes. ServusTV and ORF take turns showing the races. SRF, on the other hand, shows all races, but you have to look up on which channel. This can be SRF 2 or SRF Info. However, all websites offer a TV program, which you can quickly find out about. RTL Luxembourg also broadcasts the races and even records them. You can stream the last race for a week as a repeat. RTL Play in Belgium shows the F1 races with French commentary.
If you are traveling and on vacation in Switzerland, Luxembourg, Belgium or Austria, you can simply stream the races. The above mentioned broadcasters have the license to officially broadcast the races in their country on free TV. If you are not on location, you will get a message that the respective content may not be broadcast for legal reasons – this is then the so-called geoblocking, which you can bypass, I use here NordVPN* or CyberGhost*.
How to stream Formula 1 abroad for free on free TV?
Time needed: 15 minutes.
Follow my simple instructions and you will be able to watch the races you want online for free abroad without any problems.
- Get a VPN
Subscribe to a VPN with servers in Austria, Luxembourg, Belgium or Switzerland. It depends on what you prefer to watch over. The best VPN services offer servers in these countries anyway. The providers I recommend, NordVPN* and CyberGhost*, provide apps for Android, Windows, macOS, iOS, and Linux.
- Install the VPN on your devices
Once you have decided, download the appropriate VPN apps and install them on your device. Open the app and log in with your user data.
- Connect to one of the servers
At this point, it depends on whether you want to stream RTL / RTL Play / ORF / ServusTV or SRF. Connect to the appropriate server in the country where you want to stream Formula 1 for free on free TV.
- Open the streaming provider
Now open one of the possible F1 streams. On SRF, the races are usually broadcast on SRF 2, possibly also on SRF Info. Sometimes you have to change the channel during a Grand Prix, but the commentators announce this in the live stream.
Pro tip: You can also watch the races on free TV via RTL Luxembourg (rtl.lu). There you can watch the repeat of the last Formula 1 race for a whole week. So if you missed a race or it was broadcast at an inconvenient time for you, you can watch the Formula 1 replay there for free. However, you need an IP address in Luxembourg and you have to connect to a corresponding server.
Is watching Formula 1 abroad for free legal?
Various specialist lawyers are convinced that you are not doing anything illegal when circumventing geoblocking. You are most likely violating the terms of use of the respective streaming provider. However, you don’t have to register with any of these broadcasters, and you probably won’t be prosecuted anyway.
Instead, the streaming providers rely on so-called geographical blockades and try to detect and block your VPN. That’s why you need a reliable VPN provider with many good servers.
However, there are countries where VPNs are prohibited. What I would like to say at this point: Find out for yourself what is allowed in your location and what is not. The fact is that you can stream Formula 1 abroad via free TV, as long as you are in one of these countries.
The F1 stream with VPN does not work – solutions
Here are some tips. If the F1 stream of Formula 1 on Free TV abroad does not work, this can have several causes.
Possibly, the streaming provider has a problem. This rarely happens, but it is a possibility. Maybe there is a technical problem that you are powerless against. In this case, you can only wait or switch to another channel.
Sometimes certain streams do not work with various browsers. Try another browser and maybe that will solve your problem.
Providers are always eager to detect VPNs. It happens that a server is unmasked and then the broadcast is blocked. If this is the case, simply change the server. Disconnecting and reconnecting often solves the problem.
The best VPNs offer multiple protocols. It may be that some VPN protocols don’t work well and that’s why try to change the protocol in the app’s settings. You can also install the browser extension of the service. These are mostly proxies and they are great for streaming.
FAQ – Frequently asked questions and answers about streaming F1 for free
The bottom line is that it’s pretty easy to watch Formula 1 on free TV from anywhere if you know the right trick with VPN.
Where can I stream Formula 1 for free? You can watch Formula 1 abroad for free on all the channels mentioned above. All races are geoblocked and therefore you need a VPN with servers in the corresponding country.
Where can I watch Formula 1 replays for free? RTL Luxembourg shows the replay of the last race, but only for one week – still. This is quite useful when races are broadcast at night or very early in the morning. You don’t have to stay awake or get up early, just watch the Grand Prix when it suits you.
Can I watch F1 with a free VPN? I highly doubt it. All free VPNs have limitations. Some offer only a few Mbytes of data volume per month and with that you can’t stream a complete race. Others don’t have the servers you need. Rather take a cheap premium service and you don’t have to be annoyed.
The post Watch Formula 1 for free – abroad via Free TV appeared first on xplatform.rocks.
As a rugby fan, you can’t miss the Six Nations, the most important rugby tournament of the year. I’ll show you how you can stream the Six Nations for free abroad. For this you need a good VPN like the one from NordVPN. Licensing rights, pay-TV and geoblocking are the reasons why you can’t easily stream the Six Nations at home for free. More about this later.
These foreign streams broadcast the Six Nations on free TV:
How to stream Six Nations Rugby for free abroad
You want to stream the rugby tournament of the year for free? I’ll explain it to you with the solution via BBC and IPTV in England:
Time needed: 15 minutes.
Watch all Six Nations rugby matches – it’s free:
- You need a VPN that can bypass geoblocking
Get a reliable VPN like NordVPN or CyberGhost – these two services are known to work around geoblocking very well. ITV and BBC broadcast the games only in England and that’s why you need a VPN with local servers. Analogous for Italy, France and Ireland.
- Connect to a server
The next step is to connect to one of these servers in England. This will give you a local English IP address and it will look like you are on site.
- Find out which channel shows which game
BBC (https://www.bbc.com/) and ITV (https://www.itv.com/) usually show the matches in rotation. Find out in time, who broadcasts which match of the Six Nations. With both broadcasters you have to create an account and register for free. Registration requires you to enter a zip code in England… pick one!
- Finished!
Now you can start the free stream of the Six Nations.
Which countries participate in the Six Nations?
The Six Nations brings together the best teams from Europe. England, Wales, Ireland, Scotland, France and Italy fight each year for the coveted rugby crown. Italy is the biggest underdog in this tournament, but they are increasingly causing big surprises. Italy is improving year by year and I am curious to see who they will upset this year.
The rules of the Six Nations – Rugby rules explained in brief
You are interested in the tournament, but you have some gaps in the rules? Here briefly the scoring system of the rugby tournament, as it can cause some wonderment:
- Four points are awarded for a win.
- In case of a draw, each team gets two points.
- A team gets a try bonus point if it lays 4 or more tries in a game.
- If a team loses by 7 or fewer points, the team receives a losing bonus point.
- If a team manages a Grand Slam, i.e. wins all 5 games, then it gets 3 extra points.
The bonus points system is designed to make teams play as offensively as possible and not just give up when victory seems hopeless.
The best VPNs to watch Six Nations for free
In principle, any VPN that can successfully bypass geoblocking of one of the channels listed above will work. However, the service should deliver high speeds, otherwise Six Nations streaming is no fun. Below are two VPN providers that I have had excellent experiences with when streaming Six Nations for free.
NordVPN
The provider is perfect for streaming the Six Nations for free via the channels listed above abroad. The VPN unlocks all of the above channels and geoblocking is no longer a problem. I tested it myself with all variants and it works flawlessly.
NordVPN allows the connection of 6 devices at the same time. But it also allows you to use it on a router, which allows you to connect devices like smart TVs and game consoles to the VPN.
The service supports all popular operating systems: Windows, Android, iOS, macOS and even Linux – including Raspberry Pi.
NordVPN has an adblocker that also protects against malware, phishing and trackers.
Another special feature of NordVPN is the cloaking servers (Obfuscate). This allows the service to work even in countries with VPN blocks, such as China, Turkey, Egypt, and Russia.
The Kill Switch protects your devices in case the connection to the VPN fails accidentally. The app will immediately disconnect your Internet connection until a connection with a VPN server is restored.
You can even try NordVPN for free and risk-free because it comes with a 30-day money-back guarantee.
CyberGhost
CyberGhost is cheaper than NordVPN, but can bypass geoblocking just as well. You can also use it to unblock the above mentioned channels to watch Six Nations for free abroad without any problems.
CyberGhost allows 7 simultaneous device connections. Of course, you may also use this provider on a router to connect your Playstation, Xbox or Smart TV to it.
CyberGhost offers one of the best and most user-friendly Android apps I know of. Besides WireGuard, CyberGhost also offers OpenVPN and if you use the latter VPN protocol as TCP, stealth mode is automatically enabled.
Otherwise, there are apps for all popular operating systems: Android, iOS, Windows, macOS and Linux. There is even a GUI for the latter, and that is rather rare.
CyberGhost also has an adblocker that protects against other cyber threats – phishing, trackers and malware.
CyberGhost also offers a money-back guarantee. This is valid for 45 days.
FAQ – frequently asked questions about the Six Nations
Can I stream Six Nations Rugby for free? Yes, you can. This works with the TV channels listed above abroad.
Can I watch Six Nations Rugby with a free VPN? Probably not, and if so, then in an extremely poor quality. We run into several problems here. Most free VPNs limit the data volume and it is not enough to watch a complete game. Other free VPNs throttle the bandwidth and that’s why streaming is not possible without annoying interruptions to load the data. Another hurdle is that free VPNs only offer servers in a few countries.
Is it legal to stream the Six Nations with a VPN? You are most likely violating the terms of use of some streaming providers. In the worst case, this will lead to an exclusion from the broadcaster. However, with a VPN you are anonymous on the Internet.
VPNs are completely legal in Germany, Austria, Switzerland and Luxembourg. However, they are not a license to break the law. Even if you use a VPN, you must comply with the respective legislation.
However, there are countries where VPNs are illegal or restricted. These include China, Egypt, Turkey, Russia, Iran and so on. If you’re traveling abroad, check the laws before you go – they’re known to change.
Where will the Six Nations be broadcast for free? I only found free legal streams in England, France, Ireland and Italy. I have listed the respective channels of the free TV countries in the list at the beginning of the article.
Can I stream Six Nations on my phone or tablet? Of course it works. Either you open the websites of the services, which are of course optimized for mobile devices, or you get the corresponding apps.
With a VPN, you can watch Six Nations for free on the go and never miss a game.
The post Stream Six Nations Rugby for free abroad appeared first on xplatform.rocks.
Modern Family is a modern-day family sitcom that originally aired on ABC in 2009. The show follows the lives of three generations of a fictional family, the Dunphys.
However, Modern Family is not available on Netflix in all countries. If you’re located in a country where Modern Family is not available on Netflix, you can use a VPN to watch it.
VPNs are online services that allow you to conceal your real IP address and encrypt your traffic. This means that you can bypass Netflix’s geographic restrictions and watch Modern Family no matter where you are located.
Netflix released the Modern Family series that has become very popular. However, some people are not able to watch it because their location does not allow them to access the content. A VPN can be used to change a person’s IP address so they can watch Modern Family from anywhere. There are many different types of VPNs, and each one has its own benefits.
A VPN is a great way to keep your information safe when you are online. It can also help you get around content restrictions. Some of the benefits of using a VPN include:
– Increased privacy and security – When you use a VPN, your traffic is encrypted, which means that it is much harder for someone to track your online activities.
– Access to blocked content – If you are trying to watch Modern Family from a location that doesn’t allow it, a VPN can help you get around those restrictions.
– Reduced risk of being hacked – A VPN can help protect your devices from being compromised by hackers.
– Improved connection speeds – Some VPNs can improve your connection speeds, which can be helpful if you are trying to stream content or play games online.
When choosing a VPN, it is important to consider the different options available to you. There are many different providers, and each one offers a unique set of features. Some of the things you should consider include:
– Price – VPNs can be expensive, so it is important to find one that fits your budget.
– Number of devices supported – Not all VPNs support the same number of devices, so you will want to make sure the one you choose can be used on all of your devices.
– Location – Some VPNs are only available in certain locations, so you will want to make sure the one you choose covers the area you need it to.
– Bandwidth – The amount of bandwidth that a VPN provides can vary, so you will want to make sure you have enough bandwidth to meet your needs.
If you are looking for a VPN to watch Modern Family, there are a few things to keep in mind. First, decide what features are important to you and then find a provider that offers those features. Second, make sure the provider is trustworthy and has a good reputation. Finally, read the terms of service carefully to make sure you understand what you are getting into. By following these tips, you can find the perfect VPN for your needs.
What VPNs Are There?
There are many different VPN providers out there, each with its own unique features and benefits. Some of the most popular VPN providers include ExpressVPN, NordVPN, and CyberGhost.
How to watch Modern Family using a VPN?
Once you have signed up for a VPN service, you will need to download and install the VPN software. Then, open the VPN software and connect to a server in the US. Once you are connected, you can open Netflix and watch Modern Family. Note that some VPN providers may slow down your internet connection, so you may want to test out a few different servers before settling on one.
So if you’re looking for a way to watch Modern Family outside of the United States, using a VPN is the best option. VPNs are easy to use and provide a lot of benefits, such as privacy and security. So don’t miss out on Modern Family – sign up for a VPN today!
The post Modern Family – How to Watch Abroad? appeared first on xplatform.rocks.
Problem
On my last day in 2022 - Friday, 23. December, I received a support ticket from one customer, that our software seems to be offline and it looks like that our servers are not responding. I checked our monitoring and the server side of the customer and everything was fine.
My first thought: Maybe a misconfiguration on the customer side, but after a remote support session with the customer, I saw that it “should work”, but something in the customer network blocks the requests to our services.
Next thought: Firewall or proxy stuff. Always nasty, but we are just using port 443, so nothing too special.
After a while I received a phone call from the customers firewall team and they discovered the problem: They are using a firewall solution from “Check Point” and our domain was flagged as “phishing”/”malware”. What the…
They even created an exception so that Check Point doesn’t block our requests, but the next problem occured: The customers “Windows Defender for Office 365” has the same “flag” for our domain, so they revert everything, because they didn’t want to change their settings too much.

Be aware, that from our end everything was working “fine” and I could access the customer services and our Windows Defender didn’t had any problems with this domain.
Solution
Somehow our domain was flagged as malware/phishing and we needed to change this false positive listening. I guess there are tons of services, that “tracks” “bad” websites and maybe all are connected somehow. From this indicent I can only suggest:
If you have trouble with Check Point:
Go to “URLCAT”, register an account and try to change the category of your domain. After you submit the “change request” you will get an email like this:
Thank you for submitting your category change request.
We will process your request and notify you by email (to: xxx.xxx@xxx.com ).
You can follow the status of your request on this page.
Your request details
Reference ID: [GUID]
URL: https://[domain].com
Suggested Categories: Computers / Internet,Business / Economy
Comment: [Given comment]
After ~1-2 days the change was done. Not sure if this is automated or not, but it was during Christmas.
If you have trouble with Windows Defender:
Go to “Report submission” in your Microsoft 365 Defender setting (you will need an account with special permissions, e.g. global admin) and add the URL as “Not junk”.

I’m not really sure if this helped or not, because we didn’t had any issues with the domain itself and I’m not sure if those “false positive” tickets bubbles up into a “global defender catalog” or if this only affects our own tenant.
Result
Anyway - after those tickets were “resolved” by Check Point / Microsoft the problem on the customer side disappeared and everyone was happy. This was my first experience with such an “false positive malware report”. I’m not sure how we ended up on such a list and why only one customer was affected.
Hope this helps!
In the last months, we started to use these terms more and more at my company without discussing the concepts behind them. One day I was asked, “What do you mean by data ownership?”
The question made me realise that I don’t know how much of these concepts are understood.
These terms refer to sociotechnical concepts (some originating from Domain-driven design). They refer to one possible answer to the question: how can a product be improved and maintained in the long term? How can we avoid hunting for weeks for bugs, understanding what the code does, finding out what it should do, and hoping that fixing one issue does not lead to a new problem? How can we continue having fun instead of becoming more and more frustrated?
Real digital products address needs which were fulfilled earlier manually. Companies which survived the first years of testing the product are often innovators in their market. They have chances to stay ahead of the others, but they have the burden of solving all questions themselves. I don’t mean the technical questions; nowadays, we have a considerable toolbox we can use. But all the competitors have that toolbox too. The questions to answer are how to organise in teams and how to organise the software to reach a steady pace without creating an over-complicated, over-engineered or over-simplified solution.
How to get a grip on the increasing complexity built up in those years when the only KPI that mattered was TTM (Time-to-Market)?
Years ago, the companies creating software to help automate work answered this question with silos around the architecture: frontend, backend, processing, etc. In the meantime, it became clear that this was not good enough.
Engineers are not hired to type code but to advise and help to solve problems.
This means they should not belong to an engineering department anymore but be part of teams around different topics to handle: marketing, search, checkout, you name it. These are sub-domains or bounded contexts (depending on the importance of the subject, more than one bounded context can build the solution for the same sub-domain). These contexts and their boundaries are not fixed forever because the context changes, the market around the company changes, and the needs change. The people involved change and, finally, the effort needed changes. The best way also to define them is to take a look at how the business is organised (sales, marketing, finance, platform, developer experience, etc.) and how the companies using the product are organised (client setup, client onboarding, employee onboarding, payroll period, connected services, etc.). By aligning the software and – to get the most significant benefit – the teams to these sub-domains, you can ensure that the cognitive load for each team is smaller than the sum of all.
What are the benefits?
- The domain experts and the engineers speak the same language, the ubiquitous language of their bounded context, to use the DDD terms.
- The teams can become experts in their sub-domain to make innovation and progress easier as the problems are uncovered one after another. They can and will become responsible and accountable about their domain because they are the only ones enabled to do so.
- Each team knows who to contact and with whom to collaborate because the ownership and the boundaries are clear. (No long-running meetings and RFCs anymore by hoping to have reached everyone involved).
What does data ownership mean in this case? Data ownership is not only about which team is the only one controlling how data is created and changed but also the one controlling which data is shared and which remains implementation detail. This way, they stay empowered and autonomous: they can decide about their experiments, reworks, and changes inside their boundaries.
Data ownership also means process ownership.
It means the team which owns the data around “expenses”, for example, owns the features around this topic, what is implemented and when so that they are involved in each improvement or change regarding expenses from the beginning. This is the only way to respect the boundaries, take responsibility, and be accountable for all decisions around the software the engineers create.
Applying these concepts can’t be done overnight, mainly because it is not only about finding the (currently) good boundaries but also shifting the mindset from “let me build something” towards “I feel responsible for this part of my product”. It needs knowledge about the product and a lot of coaching and care. But finding the boundaries to start with should be doable in case of a product already established on the market and with a clear strategy. The alternatives are silos, continuously increasing cognitive load or the loss of an overview and local optimisations.