SDK

How to use the .NET CLI clean-up tools on macOS

How to use the .NET CLI clean-up tools on macOS

Earlier this week, the .NET SDK and Runtimes received some updates. Together with that, also Visual Studio for Mac was updated. Once I got past the installation of all updates, both Visual Studio and Rider were no longer restoring the required NuGet packages for my .NET MAUI project running on .NET 6.

I eventually fixed that issue by cleaning up all the .NET SDKs, Runtimes, workloads and NuGet caches on my MacBook Pro. Read on to learn about the tools I used.

.NET uninstall tool

I have been using the .NET uninstall tool in the past. Unlike on Windows, you have to download the executable from GitHub in its zipped form.

While the releases page shows some terminal commands to unpack and run the tool, they never worked for me as stated there. While I was able to make the new directory with the mkdir command, the unpacking always shows an error. So I opened up Finder and unzipped it manually with the Archive Utility app that ships with macOS.

dotnet-core-uninstall unzipping

After switching to the folder in Terminal, the tool is supposed to show the help. Instead, I got an error showing me that I am not allowed to run this app for security reasons. The OS blocks the execution. If the same happens for you, right click on the extracted executable and select “Open With” followed by “Terminal.app (default)“. This will prompt you with this screen:

app downloaded from the internet message

Once you click on “Open“, a new Terminal window appears. Close this window, it is unusable as we are already in the exited state. Instead, open a new Terminal and change to the installation folder and call the help command:

cd ~/dotnet-core-uninstall
./dotnet-core-uninstall -h
Terminal with dotnet-core-uninstall help

Now that we are able to run the tool, let’s have a look what we have installed by running the dotnet --list command. We need to call the command twice, once for the installed -sdks and once for the installed -runtimes:

dotnet --list-sdks
dotnet --list-runtimes

You may be as surprised (I was, at least) how many versions you are accumulating over time. They never get removed by newer versions (it’s by design, according to Microsoft). To get rid of all versions except the latest, run the following commands with the uninstall tool (again once for — sdk, once for –runtime):

sudo ./dotnet-core-uninstall remove --all-but-latest --sdk
sudo ./dotnet-core-uninstall remove --all-but-latest --runtime

After uninstalling all previous versions, you may have to reinstall the latest .NET 6 SDK again. You could also use the –-all-but [Versions] command to specify the versions explicitly. No matter which way you’re going, if you run the dotnet --list commands again, you should see something similar to this:

dotnet --list command

Download: https://github.com/dotnet/cli-lab/releases

Documentation: https://learn.microsoft.com/en-us/dotnet/core/additional-tools/uninstall-tool?tabs=macos#step-3—uninstall-net-sdks-and-runtimes

dotnet workload command

As I had problems getting the required NuGet packages for my MAUI app, I decided to uninstall all .NET MAUI workloads as well. First, I had a look what is installed with the list command:

dotnet workload list
dotnet workload list result

Once you have that list, you need to call the uninstall command for every single installed workload:

sudo dotnet workload uninstall macos maui-maccatalyst maui-ios maui-android ios maccatalyst maui tvos android

Once they are uninstalled, I cleared the Terminal and installed them all again using the install command:

sudo dotnet workload install macos maui-maccatalyst maui-ios maui-android ios maccatalyst maui tvos android
dotnet workload install result in Terminal

Now we have the latest .NET MAUI workload installed as well as the platform specific workloads as well.

Documentation: https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-workload

dotnet nuget locals

The final clean-up step involves all NuGet caches on your machine. Yes, you read that right, multiple caches. To see them all, run the following command:

dotnet nuget locals all --list

This will get you something like this:

dotnet nuget locals cache results in terminal

Now let’s get rid of all those old NuGet packages:

sudo dotnet nuget locals all --clear

If you’re lucky, you will see this message:

local nuget caches cleared in terminal

My first attempt was not that successful. I needed to open the global packages’ folder in Finder and delete some remaining packages manually. Only after that, I was able to run the clear command with success.

Conclusion

Neither Visual Studio nor the .NET installer perform clean-up tasks on macOS. Until Microsoft changes their mind here, we will have to clean-up old packages manually to keep our system smoothly running. Luckily, there are at least CLI tools around to help us with that job. As always, I hope this blog post will be helpful for some of you.

Until the next post, happy coding, everyone!

Posted by msicc in Dev Stories, macOS, MAUI, Xamarin, 1 comment
#CASBAN6: Function base class (and an update to the DTO models)

#CASBAN6: Function base class (and an update to the DTO models)

After we have been setting up our Azure Function project last time, we are now able to create a base class for our Azure functions. The main goal is to achieve a common configuration for all functions to make our life easier later on.

CRUD defintion

Our API endpoints should provide us a CRUD (Create-Read-Update-Delete) interface. Our implementation will reflect this pattern as follows:

  • A creation endpoint
  • Two read endpoints – one for list results (like a list of posts) and one for receiving details of an entity
  • An update endpoint to change existing entities
  • A delete endpoint

As all of our entities are tied to a single blog’s Id, we will use this base class for all entities besides the Blog entity itself.

The base class

    public abstract class BlogFunctionBase
    {
        internal readonly BlogContext BlogContext;
        internal ILogger? Logger;
        internal JsonSerializerSettings? JsonSerializerSettings;

        protected BlogFunctionBase(BlogContext blogContext)
        {
            BlogContext = blogContext ?? throw new ArgumentNullException(nameof(blogContext));

            CreateNewtonSoftSerializerSettings();
        }

        private void CreateNewtonSoftSerializerSettings()
        {
            JsonSerializerSettings = NewtonsoftJsonObjectSerializer.CreateJsonSerializerSettings();

            JsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();

            JsonSerializerSettings.NullValueHandling = NullValueHandling.Ignore;
            JsonSerializerSettings.Formatting = Formatting.Indented;
            JsonSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            JsonSerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
            JsonSerializerSettings.DateParseHandling = DateParseHandling.DateTimeOffset;
        }

        public virtual Task<HttpResponseData> Create([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequestData req,
            string blogId) =>
            throw new NotImplementedException();

        public virtual Task<HttpResponseData> GetList([HttpTriggerAttribute(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequestData req, string blogId) =>
            throw new NotImplementedException();

        public virtual Task<HttpResponseData> GetSingle([HttpTriggerAttribute(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequestData req, string blogId, string id) =>
            throw new NotImplementedException();

        public virtual Task<HttpResponseData> Update([HttpTriggerAttribute(AuthorizationLevel.Anonymous, "put", Route = null)] HttpRequestData req, string blogId, string id) =>
            throw new NotImplementedException();

        public virtual Task<HttpResponseData> Delete([HttpTriggerAttribute(AuthorizationLevel.Anonymous, "delete", Route = null)] HttpRequestData req, string blogId, string id) =>
            throw new NotImplementedException();

    }

Knowing the definition of our API endpoints, there shouldn’t be any surprises with that implementation. As a base class, the definition is of course abstract.

In the constructor, I am setting up how JSON objects will be handled. I am following common practices in formatting. The only thing that is different from using JSON.NET directly is the fact we need to explicitly use the NewtonsoftJsonObjectSerializer.CreateJsonSerializerSettings method to create an instance of the JsonSerializerSettings property.

We also have an internal ILogger? property, which will be used in the derived class to create a typed instance for logging purposes. Last but not least, I am enforcing passing in a BlogContext instance from our Entity Framework implementation.

If you look at the method declaration, you’ll see the authorization level is set to Anonymous. As I am using Azure Active Directory, I am handling the authorization on a separate layer (there will be a post on that topic as well). Besides that, there is nothing special. All methods need a blogId and those endpoints that interact with a resource need a resource id as well.

The blog entity has a similar structure, with some differences in the parameter definitions. To keep things simple, I decided to let it be different from the base class definition above. We will see this in the next post of this series.

Update to the DTO models

While the blog series is ongoing, it still lags a bit behind on what I am currently working on (you can follow the dev branch on GitHub for an up-to-date view). As I am currently working on the administration client for our blog, I started to implement an SDK that can be used by all clients (the blog’s website will also just be a client). See the original post on DTOs here.

To be able to create a generic implementation of the calls to the API endpoints, I needed to create also a base class for the DTO models. It is a very simple class, as you can see:

public abstract class DtoModelBase
{
    public virtual Guid? BlogId { get; set; }

    public virtual Guid? ResourceId { get; set; }
}

This base class allows me to specify a Type that derives from it in the SDK API calls – which was my main goal. Second, I have now a common ResourceId property instead of the Id being named after the class name of the DTO. Both properties are virtual to allow me to specify the Required attributes in the derived classes as needed. You can see these changes on GitHub.

The reason I am writing about the change already today is that it will have impact on how the functions are implemented, as both the API functions and the Client SDK use the same DTO classes.

Conclusion

In this post, we had a look at the base class for our Azure functions we will use as an API and on the updated DTO models. With this prerequisite post in place, we will have a look at the function implementations in the next post.

Until the next post, happy coding, everyone!

Posted by msicc in Azure, Dev Stories, MAUI, 1 comment

Bing Maps SDK on Windows 8 (W8CP)

With the release of the Windows 8 Consumer Preview, it was only a matter of time that Microsoft releases some new SDKs to us developers. We are starting with the Bing Maps SDK.

Bing Maps SDK for Windows 8 Metro style apps

Screenshot (32)

Microsoft´s Bing Maps team released a new SDK for Windows 8. You can use the SDK free and unlimited during the preview period.

The new SDK supports Java by using the AJAX v7 controls, and provides all standard items like map types, pushpins, infoboxes and tile layers. Additionally there is now a venue Maps module. At the moment there are still some missing bits like directions, traffic and overlays. Your maybe previous used REST APIs will still work and help you to use more features. If you want to learn on an example, you can watch this site.

Of course you can also use C#, C++ or Visual Basic to create apps that are using the SDK. The SDK now supports client vendor rendering as well as full hardware acceleration.You can also use Aerial and  Bird´s eye view and traffic overlays  within you app. Some features are in this early stage US only. You can learn on an example on this MSDN page.

Getting started…

OC course, you need to download the SDK to get started overall:  http://visualstudiogallery.msdn.microsoft.com/0c341dfb-4584-4738-949c-daf55b82df58. You can also use the VS11 Extension Manager to download the SDK.

Secondly, you will net a special “Metro style  apps (BETA) key” to use the SDK within you apps. Get your key at www.bingmapsportal.com .

If you want to read a lot more about using Bing Maps within you Metro styled apps, head over to the documentation sites at MSDN.

Posted by msicc in Archive, 0 comments

WPDEV on W8CP: How to install the Windows Phone SDK

Yesterday I was all day playing around with the Windows 8 Consumer Preview (W8CP) as many of us.

Screenshot

Today I wanted to get a bit more serious and tried to install the Windows Phone SDK.

Once downloaded from App Hub, I clicked “Install”, and waited for the SDK to complete  . Install went trough, and I was waiting for opening my current project.

But then I was shocked by numerous error messages, all of the regarding XNA plugins and updates. So the dream was over. The SDK does not support W8CP.

screen

I am a very Metro-addicted man, so I was searching for a solution. On Twitter I was tipped by @nikovrdoljak to one part of the solution.

The errors are caused by Games for Windows – LIVE Redistributable

XNA Game Studio installs a version of the Games for Windows – LIVE Redistributable behind the scenes.  Some older versions of the Games for Windows – LIVE Redistributable attempt to install and use a file that is being installed by Windows 8, and the older versions of the redistributable are not compatible with the newer version of the file that is installed by Windows 8.  Newer versions of the Games for Windows – LIVE Redistributable are compatible with Windows 8, and if you pre-install the new redistributable before installing XNA Game Studio, setup will recognize that it is already there and use the new version instead of trying to install the old version.

The reason this issue also impacts the Windows Phone SDK 7.1 is that this SDK installs XNA Game Studio behind the scenes, which in turn installs the Games for Windows – LIVE Redistributable behind the scenes.

So where to download the actual version? Let´s check this later. I followed the steps shown on Aaron Stebner’s WebLog. But that was not all.

I think more WPDev are willing to try, so here is a checklist:

  • uninstall all parts of the Windows Phone SDK – Note: there are some bits left after you use the automatic install, so you have to uninstall remaining parts of the SDK manually
  • do a reboot (that thing you do not want to do once you started playing around with W8CP). Don´t worry, it is faster as on Windows 7 (on my 2 year old ASUS under one minute).
  • go to the Games for Windows download page, which you can find on this page: http://www.xbox.com/de-DE/LIVE/PC/DownloadClient. Replace the “de-DE”-part with your regional language code, for the US p. e. “en-US” to download the correct version of the redistributable.
  • start installation
  • in the middle of the installation, the UAC asks you to allow the installation. Now click on “change, when this message appears” (the original wording might be slightly different, I translated it from German).
  • pull down the switch to set Windows to not ask you anymore (yes, even if this is not recommended)
  • now let the installation of Games for Windows –LIVE Redistributable finish.
  • finally, start installation of the Windows Phone SDK. This time, it takes a little longer than before (probably due to the now working install parts)
  • if you want to, turn the UAC on again (control panel/more settings/users/settings for user access control)

Congrats, you installed the Windows Phone SDK, but…

you still have to deal with some points:

  • the SDK currently works only with Visual Studio 2010
  • the emulator does not work, so you have to debug on device
  • the updated Windows Phone SDK 7.1.1 (which is only to have a look, not the final version), might afford additional steps

For me it only worked with above mentioned steps. If you had another steps to do or additional information, leave a comment to discuss.

happy coding on Windows 8, everyone!

Posted by msicc in Archive, 6 comments