26 Jan 2025 #writing
“Money has already been made, we just have to get out and search for it.”
That’s a common phrase in my hometown. It means money rewards action. And like I learned from hearing and watching James Altucher, nobody wakes up and thinks about giving money to any of us. We have to search for it.
That applies to content ideas too. Replace “money” with “content” and you’ll get the same meaning.
When we wear our writer (or creative) glasses, there’s content everywhere:
- Books
- Questions
- Conversations
- Emails you reply to
- Projects you’re working on
- Comments you leave on social media
- Other people’s posts
- Situations at work
- TV shows
Everywhere.
For example, the other day I realized the same coworker had asked the same question about investing on a WhatsApp group. Then I wrote about it.
Another coworker asked me how to start writing on LinkedIn. Then I wrote about it.
Another day I was reading a book review. And I realized I had read the same book. I stopped reading and wrote my own review.
Another day I found a post I didn’t agree with. Then I wrote a reaction.
I felt guilty for binge-watching my favorite TV shows until I started to write about them. Now watching Netflix and TV shows is an excuse to write more content. Content is everywhere.
25 Jan 2025 #csharp #asp.net
Here’s an opinionated catch-up guide if you missed the last decade of the C#/.NET/Microsoft evolution.
#1. C# isn’t JAVA anymore. That joke doesn’t work anymore. The two languages have taken completely different paths. They don’t even look the same.
#2. There’s a new runtime: .NET. It’s multiplatform and open-sourced. We have the classic one, we call it: .NET Framework, which you probably already know. And the new one was called “.NET Core.” But now, it’s simply “.NET” Yes, naming is hard.
#3. Speaking of the language, the main language features are still there. C# is an imperative side-effect-heavy language. But with every release, it’s adopting more features from functional languages, like lambda expressions, pattern matching, and records. (See #7)
#4. There’s excellent support for asynchronous methods with two keywords: async
and await
.
#5. There’s a whole lot of new small language features. Apart from async
/await
(from C# 5.0) we haven’t had a release with a single major feature. Most of the new features are syntactic sugar for existing features.
#6. There’s a new feature you shouldn’t miss: nullable references. It should have been called: “non-nullable references” instead. Do you remember nullable primitive types? Like int?
? We allow a type to contain null by appending a ?
when declaring it. We can do the same for classes. So Movie? m
can be null, but Movie m
can’t. And the compiler warns us when we’re trying to use a reference that might be null. Awesome!
#7. I compiled a list of C# features we should know about. Those are the features I like and have used the most.
#8. A “Hello, world” is now literally one line of code. We don’t need to declare a class and a Main method for console applications. Just write your code directly in a file like in a scripting language.
#9. I stopped expanding that list with the most recent features. C# is getting bloated with more features that are making the language less consistent. I don’t like that.
#10. The same way we have a new runtime, we have a new web framework: ASP.NET Core. It was a full rewrite of the classic ASP.NET. There’s no Global.asax, web.config, or files listed on csproj files. If you knew and used the old ASP.NET, I wrote a guide with the difference between the two. With .NET, we have way better tooling like a command line interface to create projects.
#11. Well, there’s Xamarin, MAUI, Blazor… But unless you’re planning to do front-end work, you don’t need to worry about them. Microsoft is still trying to find, create, and establish a golden hammer for the front-end side.
Sure, I’m missing a lot of other things. But you’re safe catching up on those.
24 Jan 2025 #csharp #todayilearned
Another day working with AutoMapper, another day with an edge case.
Let’s say we have class CreateMovieRequest
with three properties: name, release year, and another property I don’t want to map, for some reason. And a destination class, Movie
, with more properties apart from those three and names using a prefix.
Simply trying to use CreateMap<CreateMovieRequest, Movie>()
won’t work. AutoMapper will warn you about unmapped properties in the destination type. “Unmapped members were found. Review the types and members below.”
Here’s how to map two classes ignoring the unmapped properties in the destination type and with prefixes:
using AutoMapper;
namespace TestProject1;
[TestClass]
public class IHateYouWilWheaton
{
public class CreateMovieRequest
{
public string Name { get; set; }
public int ReleaseYear { get; set; }
public string IDontWantThisOneMapped { get; set; }
}
public class Movie
{
// These two aren't mapped from the source
public int Id { get; set; }
public int DurationInMinutes { get; set; }
// These two have the 'Movie' prefix
public string MovieName { get; set; }
public int MovieReleaseYear { get; set; }
}
[TestMethod]
public void IgnoringNotMappedProps()
{
var config = new MapperConfiguration(cfg =>
{
// Let's keep it here, shall we?
cfg.RecognizeDestinationPrefixes("Movie");
// ^^^^^
// To avoid explicitly mapping the fields because of the prefix
// Before:
// cfg.CreateMap<CreateMovieRequest, Movie>();
// ^^^^^
// AutoMapper.AutoMapperConfigurationException:
// Unmapped members were found. Review the types and members below.
// ...
// Unmapped properties:
// Id
// MovieName
// DurationInMinutes
//
//
// After:
cfg.CreateMap<CreateMovieRequest, Movie>(MemberList.Source)
// ^^^^^
// To validate unmapped properties on the source type
// Possible options: Source, Destination, and None
.ForSourceMember(src => src.IDontWantThisOneMapped, opt => opt.DoNotValidate());
// ^^^^^
// Since I don't want this one mapped for some reason
});
config.AssertConfigurationIsValid();
var source = new CreateMovieRequest
{
Name = "Space Odyssey",
ReleaseYear = 1968,
IDontWantThisOneMapped = "Ok, if you say so"
};
var mapper = config.CreateMapper();
var destination = mapper.Map<Movie>(source);
Assert.AreEqual(destination.MovieName, source.Name);
Assert.AreEqual(destination.MovieReleaseYear, source.ReleaseYear);
}
}
The trick for prefixes is RecognizeDestinationPrefixes()
and the one for warnings is passing any of Source
, Destination
, or None
as a parameter to Map()
.
And to ignore an “incoming” property, ForSourceMember()
, with DoNotValidate()
.
Et voilà!
23 Jan 2025 #writing
Is it a best-selling book? A Pulitzer-winning novel? A large newsletter? More than 1,000 articles published anywhere online?
When can we call ourselves “writers”?
I have to confess I’ve been reluctant to use “digital writer” or “technical writer” or “writer” as a title anywhere online, even though I’ve been writing in my small corner of the Internet since 2018.
But recently, watching this interview with Devon Eriksen on YouTube, I changed my mind about using the title “writer.” He says:
If you’ve written and you’ve gotten paid for it. You’re a writer.
After hearing that, I wasn’t afraid to change my tagline on social media and here on my blog.
Definitely, someone has asked me to write something and paid me for that. That was by pure accident or luck, thanks to sharing the tutorials I write here on my blog. That’s how I made my first internet money.
You don’t need to publish a book. Well, publishing a book isn’t that hard these days. James Altucher has a strategy to publish a book in 30 days.
You don’t need to write and publish a book to call yourself a writer. Find one person that will pay to write and start calling yourself a “writer.” I’m a writer. And you?
22 Jan 2025 #csharp #todayilearned
TL;DR: For nullable columns with default constraints, you have to tell EntityFramework the default value of the mapping property via C#. Otherwise, when you create a new record, it will have NULL instead of the default value in the database. You’re welcome! Bye!
Let’s create a dummy table with one nullable column but with a defualt constraint
Let’s create a new Movies
database with one table called Movies
, with an Id, a name, and a director name as optional, but with a default value. Like this,
CREATE DATABASE Movies;
GO
USE Movies;
GO
CREATE TABLE Movies (
Id INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(100) NOT NULL,
DirectorName NVARCHAR(100) DEFAULT 'ThisIsADefaultValue'
);
GO
Let’s create a new record (without the nullable column) and read it back
Now to prove a point, let’s use EntityFramework Core to insert a new movie without passing a director name and read it back.
What will be the value of DirectorName
once we read it back? Null? The value inside the default constraint? Make your bets!
Here we go,
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace TestProject1;
[TestClass]
public class EntityFrameworkAndDefaults
{
[TestMethod]
public void TestInsertAndReadMovie()
{
const string connectionString = $"Server=(localdb)\\MSSQLLocalDB;Database=Movies;Trusted_Connection=True;";
var dbContextOptions = new DbContextOptionsBuilder<MoviesContext>()
.UseSqlServer(connectionString)
.Options;
using (var context = new MoviesContext(dbContextOptions))
{
var inception = new Movie
{
Name = "Inception"
// No director name here...
// ^^^^^
};
context.Movies.Add(inception);
context.SaveChanges();
}
using (var context = new MoviesContext(dbContextOptions))
{
var movie = context.Movies.FirstOrDefault(m => m.Name == "Inception");
Assert.IsNotNull(movie);
Assert.AreEqual("ThisIsADefaultValue", movie.DirectorName);
// ^^^^^^^^
// Assert.AreEqual failed. Expected:<ThisIsADefaultValue>. Actual:<(null)>.
//
// Whaaaaat!
}
}
}
public class MoviesContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
public MoviesContext(DbContextOptions<MoviesContext> options)
: base(options)
{
}
}
public class Movie
{
public int Id { get; set; }
public required string Name { get; set; }
public string? DirectorName { get; set; }
}
Ok, to my surprise that test fails. movie.DirectorName
isn’t "ThisIsADefaultValue"
. It’s null.
I was expecting to see the value from the default constraint in the database. But, no. Wah, wah, wah, Wahhhhhhh…
Here you have it EntityFramework. Can I get my default value now?
We have to tell EntityFramework Core the default value of our column, like this,
public class MoviesContext : DbContext
{
public DbSet<Movie> Movies { get; set; }
public MoviesContext(DbContextOptions<MoviesContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// For simplicity, let keep it here...
modelBuilder.Entity<Movie>(entity =>
{
entity
.Property(e => e.DirectorName)
.HasDefaultValueSql("ThisIsADefaultValue");
// ^^^^^
// Here you have it EntityFramework Core
// Can I get my default value now?
});
}
}
This behavior only adds up to my love and hate relationship with EntityFramework Core.
Et voilà!
Starting out or already on the coding journey? Join my free 7-day email course to refactor your software engineering career now–I distill 10+ years of career lessons into 7 short emails.