Default ASP.NET Core port changed from 80 to 8080 in .NET8 => API project deployment / health check failure
This change has wasted my DevOps Colleague a lot of time. I hope this information could help more people.
This change has wasted my DevOps Colleague a lot of time. I hope this information could help more people.
Deploying a Flutter web application to GitHub Pages is a straightforward process, but integrating a custom domain can sometimes introduce challenges. Recently, I faced an issue where my Flutter web app, which deployed perfectly to the default GitHub Pages URL, stopped working after setting up a custom subdomain. Here's a step-by-step guide on how I resolved this issue, which might help others facing the same problem.
I had a Flutter web app named "HappyNotes" hosted on GitHub Pages. The GitHub Actions workflow used to build and deploy the app looked like this:
name: Deploy HappyNotes Web
on:
workflow_dispatch:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.x'
channel: 'stable'
- name: Build web
run: |
cp .env.production .env
flutter config --enable-web
flutter build web --release --base-href "/HappyNotes/"
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.RELEASE_TOKEN }}
publish_dir: ./build/web
This workflow worked flawlessly with the default URL: https://shukebeta.github.io/HappyNotes
.
After setting up a custom subdomain happynotes.shukebeta.com
, the app stopped working. The root cause of this issue involved multiple configuration steps that needed to be adjusted for the custom domain to work properly.
Here’s how I resolved the issue:
First, I ensured that the DNS settings were correctly configured:
DNS Provider Configuration:
happynotes.shukebeta.com
pointing to shukebeta.github.io.
(attention: the last .
after io
is important!)Next, I checked the GitHub Pages settings:
Custom Domain Setup:
happynotes.shukebeta.com
.To ensure GitHub Pages recognized the custom domain, a CNAME
file will be needed to put into the build/web
directory. I automated this step in the GitHub Actions workflow:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.x'
channel: 'stable'
- name: Build web
run: |
cp .env.production .env
flutter config --enable-web
flutter build web --release --base-href "/"
- name: Create CNAME file
run: echo 'happynotes.shukebeta.com' > ./build/web/CNAME
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.RELEASE_TOKEN }}
publish_dir: ./build/web
Since the custom subdomain serves the app from the root, the base-href
parameter is also needed to adjust:
- name: Build web
run: |
cp .env.production .env
flutter config --enable-web
flutter build web --release --base-href "/"
that's it.
Today, I created another workflow file to deploy my side project to the production environment. Here's a simple memo for what I have done.
Setup a new domain name on <cloudflare.com>
Setup a GitHub runner on the target VPS (this step is not really necessary, I can use an existing runner, but then I'll need to cope with coping built result to the target VPS )
sudo ./svc.sh install
sudo ./svc.sh start
Create a work-flow file in the .github/workflow
folder, and set
on:
workflow_dispatch
For your reference, here the whole workflow file, and as I mentioned before, this article helped me a lot.
name: Deploy to the production env
# Controls when the workflow will run
on:
workflow_dispatch:
jobs:
deploy:
# Our previously created self-hosted runner
runs-on: [self-hosted, linux, racknerd]
strategy:
matrix:
dotnet: ["8.0.x"]
# A sequence of tasks that will execute as part of the job
steps:
# Checks out repository so our job can access it
- uses: actions/checkout@v4
- name: Setup .NET Core SDK ${{ matrix.dotnet-version }}
uses: actions/setup-dotnet@v4
with:
ref: ${{ github.event.inputs.tag }}
dotnet-version: ${{ matrix.dotnet-version }}
- name: Install dependencies
run: dotnet restore
- name: Build
run: dotnet build --configuration Release --no-restore
- name: Publish
run: dotnet publish -c Release --property:PublishDir=/a-target-folder/HappyNotes.Api
- name: Replace credentials
run: |
pwd
sed -i "s/password-placeholder/${{ secrets.PRODUCTION_MYSQL_PASSWORD }}/g" /a-target-folder/HappyNotes.Api/appsettings.json
sed -i "s/symmetric-security-key-placeholder/${{ secrets.PRODUCTION_SYMMETRIC_SECURITY_KEY }}/g" /a-target-folder/HappyNotes.Api/appsettings.json
sed -i "s/staging-happynotes-api.dev/happynotes-api/g" /a-target-folder/HappyNotes.Api/appsettings.json
- name: Restart the app
run: |
echo $XDG_RUNTIME_DIR
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user restart HappyNotes.Api.service
IMHO, using a tool should be the solution.
When building user interfaces in Flutter, it's often desirable to have the keyboard automatically pop up and focus set on a specific TextField when navigating to a new page or rendering a widget. This auto-focus feature can greatly improve the user experience by allowing users to start typing immediately without having to manually tap on the TextField to focus it.
In this blog post, we'll explore how to implement the auto-focus feature for TextFields in Flutter using FocusNodes.
Step 1: Create a FocusNode
The first step is to create a FocusNode instance, which represents the focus state of a particular widget. You can create a FocusNode in the initState method of your StatefulWidget:
late FocusNode myFocusNode;
@override
void initState() {
super.initState();
myFocusNode = FocusNode();
}
Step 2: Associate the FocusNode with the TextField
Next, you need to associate the FocusNode with the TextField you want to focus. You can do this by passing the FocusNode to the focusNode property of the TextField:
TextField(
focusNode: myFocusNode,
// other properties
)
Step 3: Request Focus on the FocusNode
To set the focus on the TextField, you need to request focus on the FocusNode. The best place to do this is after the widget has been rendered, which you can achieve using the WidgetsBinding.instance.addPostFrameCallback method:
@override
void initState() {
super.initState();
myFocusNode = FocusNode();
WidgetsBinding.instance.addPostFrameCallback((_) {
myFocusNode.requestFocus();
});
}
The addPostFrameCallback method ensures that the focus request is made after the widget has been rendered, which is necessary to avoid any potential issues with focus management.
Example Implementation
Here's an example implementation of a StatefulWidget that demonstrates the auto-focus feature for a TextField:
class NewNoteState extends State<NewNote> {
final TextEditingController _noteController = TextEditingController();
final FocusNode _noteFocusNode = FocusNode();
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
_noteFocusNode.requestFocus();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Note'),
),
body: Column(
children: [
TextField(
controller: _noteController,
focusNode: _noteFocusNode,
keyboardType: TextInputType.multiline,
// other properties
),
// other widgets
],
),
);
}
@override
void dispose() {
_noteController.dispose();
_noteFocusNode.dispose();
super.dispose();
}
}
In this example, we create a FocusNode called _noteFocusNode and associate it with the TextField. In the initState method, we use WidgetsBinding.instance.addPostFrameCallback to request focus on the _noteFocusNode after the widget has been rendered. This will automatically set the focus on the TextField when the NewNote widget is rendered.
Conclusion
Adding the auto-focus feature to TextFields in Flutter can greatly enhance the user experience by allowing users to start typing immediately without having to manually tap on the TextField to focus it. By creating a FocusNode, associating it with the TextField, and requesting focus on the FocusNode after the widget has been rendered, you can easily implement this feature in your Flutter applications.
Remember to dispose of the FocusNode when it's no longer needed to avoid memory leaks. Additionally, be mindful of potential issues with focus management and use the appropriate methods and callbacks to ensure smooth focus handling in your application.