Sunday, December 22, 2019

Android Room Database Subsequent Insert Failed Due to Broken AutoIncrement

Room DB has managed to abstract away complicated SQL statements which is pretty nice. But as with other new things, it takes a while to get used to.

Problem

It all starts with an entity such as the following:
@Entity
data class Item(
    @PrimaryKey(autoGenerate = true) val id: Int = Int.MIN_VALUE,
    @ColumnInfo val name: String?
}

and my Dao has the following function:
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(item: Item)

The first insert went well, but I noticed my subsequent insert failed. 

Solution

For somewhat reason, it tried to assign the same value as Id. After few trial and error, I managed to fix it by changing the Int.MIN_VALUE to 0. So the entity class becomes:

@Entity
data class Item(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo val name: String?
}

Tuesday, December 3, 2019

"Specify one workspace" - Deleting Team Foundation Phantom Workspace

One day, my colleague somehow discovered a duplicate team foundation workspace in his computer after rebooting his PC.

Problem

The duplicates make him unable to find the projects tied to remote repository that he is working on. The duplicated workspace has exactly the same name, owner and computer name as the other one except no existing mapping. Worse, Visual Studio detected only one workspace and deleting it doesn't seem to work.

We started with tf.exe command after we figure out that we can manage workspaces using command line. Using the following command, we manage to get a list of all workspaces:

tf workspaces /collection:<domain>.visualstudio.com\<organization> /owner:*

But our attempt to delete the particular workspace using the following command failed with the message "Specify one workspace":

tf workspace /delete <workspace_name>;<domain>\<owner_name>

Solution 

After browsing more, we found this thread: https://developercommunity.visualstudio.com/content/problem/267507/cant-delete-an-abandoned-vsts-workspace.html

Basically, we can get a certain ID to differentiate the two workspaces. But to manage workspaces, we need "Administer workspaces" permission. It took us a while to figure out how to give ourselves the permission. To do that we did the following steps:

  1. Log in to Azure DevOps console.
  2. Select the organization to go to the organization level page.
  3. On the bottom left of the console, click on the "Organization settings".
  4. Under Security > Permissions, select "Project Collection Administrators" group.
  5. Add ourselves (users) as member of that group.
Once permission was setup, we can then run the following command to get a list of all workspaces in xml format:

tf workspaces /collection:<domain>.visualstudio.com\<organization> /owner:* /format:xml

However, we bumped into another issue. My colleague's tf.exe somehow doesn't support the /format:xml option. And I found out that mine does. It turns out that his tf.exe was located at:

C:\Program Files (x86)\Microsoft Visual Studio 15.0\Common7\IDE\

while mine was located at:

C:\Program Files (x86)\Microsoft Visual Studio\<year>\<edition>\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\

So, I managed to retrieved the xml format and the owner alias of both workspaces. I deleted both of them using the following command:

tf workspace /delete <workspace_name>;<owner_alias> /collection:<domain>.visualstudio.com\<organization>

We also found out that the difference between both of them are two different email addresses, so we deleted one of the accounts from Visual Studio (on the top right) to make sure only one of them remained.

Other thing that didn't work for us initially was trying to rename the visible workspace in Visual Studio. We are hoping by renaming one of them, we can differentiate them and delete one of them. But seems like there is a cache that got in our way that the delete command still didn't work even after we managed to rename it.

Other reference links:


Wednesday, November 27, 2019

Moving ASP.NET Session State Server to Aurora/MySQL

Our database was in MS SQL Server and we were in the middle of moving to Aurora with MySQL compatibility.

Problem

And obviously there are differences to be resolved and one of them is we are not sure on how to move the ASP.NET Session state.

Solution

After several troubleshooting sessions (pun not intended), I finally managed to move the session state server to Aurora. The following two webpages have been very helpful, albeit the first one is outdated:


My steps are as follow:

1. Disable the current state server by commenting/removing the sessionState tag under system.web in web.config.
2. Add MySql.Web Nuget package (As of this post, the working one is version 8.0.17).
3. Add new sessionState tag under system.web

<sessionState mode="Custom" customProvider="MySqlSessionStateStore"> 
   <providers> 
      <add name="MySqlSessionStateStore" type="MySql.Web.SessionState.MySqlSessionStateStore, MySql.Web, Version=8.0.17.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" connectionStringName="LocalMySqlServer" applicationName="/" autogenerateschema="True" />
</providers> 
</sessionState>

Note the necessary attributes:

  • mode="Custom"
  • customProvider="<provider_name>"
  • autogenerateschema="True"
4. Add connection string. I would prefer to do this programmatically but I can't find a way to do it as of this post. Also, database has to be specified in the connection string.
5. Create schema/database in Aurora/MySql. I found out that MySql.Web doesn't automatically create the schema/database but it will generate necessary tables.

That is all to get it to work for me. 

Another thing to note is the autogenerateschema attribute was not available through autocomplete/intellisense. However, I can find some other attributes as properties of MySqlSessionStateStore class.



Install Previous Version of Nuget Package that is not Visible

Sometimes a new software version also introduces a new bug and we need to rollback. And this time is on one of the Nuget package that we use.

Problem

When troubleshooting MySql Nuget package issue, I noticed that I can't revert back to the previous version using the version drop down under Nuget manager window in Visual Studio. 

Solution

So, a bit of searching reminds me that I can use the Package Manager Console to install a package. Maybe I can specify the version and the server still has it. So I uninstall the latest package and ran the following command:

Install-Package <package_name> -Version <version> -Source nuget.org

The source option is optional. In my case, somehow I had it defaulted to some other source so I have to actually specify it in the command. Hit enter and I got the previous version installed. Problem solved!

Thursday, November 14, 2019

Convert FAT32 to NTFS with No Data Loss in Windows

Filesystem is as usual a pretty complicated thing. And I happened to have a new external hard drive that for somewhat reason was formatted as FAT32. Of course, I didn't notice until I put a bunch of data in it. 

Problem

The time has come when I need to store file larger than the 4GB limit of FAT32. 

Solution

So browsing around the internet, I found out that I can convert to NTFS without data loss and third party software from https://www.tenforums.com/tutorials/85893-convert-fat32-ntfs-without-data-loss-windows.html.

The steps that I took are:

  1. Make sure data are backed up somewhere else.
  2. Close all software/application that has the drive opened. I closed the File Explore too.
  3. Run command prompt as administrator.
  4. Run the following command in command prompt: convert <drive> /fs:ntfs. For example: convert D: /fs:ntfs
  5. Restart the computer.
That's it!



Wednesday, November 13, 2019

Kernel not Updated on Ubuntu 14.04 in AWS EC2 Nitro-based Instance

Sometimes a simple thing which works for many others doesn't work for us and this time it is on updating the Linux kernel.

Problem

It is all started when we are trying to migrate an m1 to t3. We are aware that t3 is a Nitro-based instance thus NVMe and ENA module have to be installed. Even after following AWS documentation, the modules don't seem to be installed properly even after reboot. Then the journey begins.

 First, I ran the following command to check what kernel is actually loaded:

uname -r

In this particular case, it returns: 3.13.0-45-generic. And I know that it is not the latest. So, as suggested by Amazon support, I ran the following commands one by one to see if the latest linux-aws package are properly installed and at the latest and nvme driver is loaded into the kernel (NVME driver is set to 'Y') 

sudo apt-cache policy linux-aws

ls -al /boot/

cat /boot/config-4.4.0-1044-aws |grep -i "nvme"


And the result are all as expected. The latest kernel is installed and nvme driver is loaded, but somehow the latest kernel is not used. I ran the following command to confirm.

dpkg -l | grep 'linux-image-'

On the amazon kernel, it starts with ii so it is indeed properly installed. Searching more online, some people manage to get the latest kernel installed and loaded using a combination of the following commands:

sudo apt-get update (update packages)

sudo apt-get install linux-generic (install meta package which was missing from my instance)

sudo apt-get install --reinstall linux-image-4.4.0-1044-aws (replace the last part with the latest kernel to reinstall)

sudo apt-get autoremove (clean up)

sudo apt-get install -f (force install missing packages)

update-grub (update grub)

None seems to work for me. 

Solution

After several days, I was wondering if somehow it has something to do with grub. So I start checking the result of the update-grub command and found out that it tries to update /boot/grub/menu.lst. That means it is using grub-legacy. So, I ran the command to check for the content menu.lst:

cat /boot/grub/menu.lst

To my surprise, none of the latest kernels are actually configured in there. In other words, the menu.lst is not updated properly. Few more online search brought me to the following article https://ubuntuforums.org/showthread.php?t=873448. Seems like there is a case which will trigger a bug. Hence menu.lst is not updated. So I make a quick copy and re-run update-grub.

cp /boot/grub/menu.lst /boot/grub/menu.lst.bak
rm /boot/grub/menu.lst
update-grub

And checking the menu.lst once again results in the latest kernel being updated in there. Restarting the instance and voilĂ ! The latest kernel is loaded and converting it to t3 was successful.





Wednesday, October 16, 2019

ASP.NET Web Forms, Auth0 and OWIN

Sometimes supporting an old technology is much more troublesome, but when you manage to overcome the challenge, you will be feeling so much more satisfied.

Problem

My boss wants to use Auth0 for authentication, but the application that we need to modify is in ASP.NET Web Forms and there is no Auth0 quickstart for ASP.NET Web Forms and I can't find an example online.

Solution

I remember I saw somewhere that we can use OWIN on ASP.NET Web Forms with a bit of tweaking. Following the awesome blog post below, I managed to get OWIN to work.


Next, I followed Auth0 quickstart for ASP.NET (OWIN)

https://auth0.com/docs/quickstart/webapp/aspnet-owin/01-login#configure-auth0

One thing to note, the RedirectUri specified in the app has to be registered in Callback URLs in the Auth0 account.

Then comes the customization. First, I need to be able to secure pages. Reading online, I found out that simply adding the following to web.config works great. Notice the authentication tag with mode set to None.

    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
      <authentication mode="None"/>
    </system.web>

Second, I need to capture the redirect. Based on the Auth0 quickstart, whenever a secure page is requested, it will redirect to https://domain_name/Account/Login. For somewhat reason when I change this path under LoginPath in the quickstart, it doesn't change the redirection at all. So I decided to leave it as is.

Per my understanding, unless FriendUrls is enabled in ASP.NET Web Forms, /Account/Login won't work properly. That means I have to handle it manually. At a glance, my options are HTTP Module or OWIN Middleware. Since I already have OWIN installed, I wrote a custom OWIN Middleware.

https://www.hanselman.com/blog/IntroducingASPNETFriendlyUrlsCleanerURLsEasierRoutingAndMobileViewsForASPNETWebForms.aspx

There are many ways in writing custom middleware, so I just picked one.

https://benfoster.io/blog/how-to-write-owin-middleware-in-5-different-steps

On my middleware Invoke method, I have the following:

public async override Task Invoke(IOwinContext context)
{
       if (context.Request.Uri.AbsolutePath.Equals("/Account/Login", StringComparison.OrdinalIgnoreCase))
       {
             string auth0RedirectUri = ConfigurationManager.AppSettings["auth0:RedirectUri"];
             context.Authentication.Challenge(new AuthenticationProperties
            {
                RedirectUri = auth0RedirectUri
            }, "Auth0");
        }
        else
        {
              await Next.Invoke(context);
         }
}

Then I register my middleware after app.UseOpenIdConnectAuthentication() in Auth0 quickstart with code similar to the following:

app.Use(typeof(CustomMiddleware));

And that's it. So far, it has been working well.

Monday, August 26, 2019

Amazon Aurora Serverless "The provider did not return a ProviderManifestToken string" Error

We had a good working application which connect to Amazon Aurora Serverless pretty well and just recently it started to intermittently unable to connect with the error "The provider did not return a ProviderManifestToken string". The following is some spec of the application:
  • .NET Framework 4.6.2
  • MySQL.Data 6.10.9
  • MySQL.Data.Entity 6.10.9
  • EntityFramework 6.2.0 (EF6)

Problem

When I debugged the application, it has inner exception which has the message: "Sequence contains more than one matching element". Upon more troubleshooting, I remember that Aurora Serverless is a cluster and it requires at least 2 subnets which reside in 2 different Available Zones. Amazon does not recommend the use of IP address instead provide us with an endpoint to connect to the cluster. That means, the endpoint might resolve to two IP addresses.

So, I decided to see what DNS lookup will show and indeed, the endpoint resolves to two IP addresses. Hence, my suspect is the MySQLConnection was expecting a single IP and receive two instead from the URL and thus throws an error. I tried to replace the endpoint in the connection string with one of the IP addresses and no error, but that is not the expected solution.

Additionally, there are intermittent errors with the following message:
Authentication to host '...' for user '...' using method 'mysql_native_password' failed with message: Reading from the stream has failed

Solution

With more reading, I stumbled upon the following article:


At the end of the articles, it says "If you use the mysql client to connect, currently you must use the MySQL 8.0-compatible mysql command."

I then realized that I have been using MySQL.Data version 6.10.9 and that might need an update. However, there is no MySQL.Data.Entity with major version of 8 which I found out later that it has been changed to MySQL.Data.EntityFramework for .NET Framework application (for .NET Core application, use MySQL.Data.EntityFrameworkCore). So I put the endpoint back into the connection string and update the Nuget packages to:
  • MySQL.Data 8.0.20 8.0.17 
  • MySQL.Data.EntityFramework 8.0.20 8.0.17
And this time, the application is finally able to connect successfully. As a side note, MySQL Workbench with major version of 8 that can connect just fine.

Additionally, we need to have a custom DbExecutionStrategy to handle the error that might happen, possibly because of cut-off connection due to scaling, and retry. In my case, it is like the following:

Public Class MyCustomDbExecutionStrategy
Inherits DbExecutionStrategy

    Sub New(maxRetryCount As Integer, maxDelay As TimeSpan)
        MyBase.New(maxRetryCount, maxDelay)
    End Sub

    Protected Overrides Function ShouldRetryOn(exception As Exception) As Boolean
        Return exception IsNot Nothing AndAlso exception.Message.Contains("Reading from the stream has failed")")
    End Function
End Class

And the custom DbExecutionStrategy has to be applied manually as follow:

Dim executionStrategy As New MyCustomDbExecutionStrategy(5, TimeSpan.FromSeconds(15))
executionStrategy.Execute(
    Sub()
        Using dbContext = New MyDbContext()
        ...
        End Using
    End Sub)

Please refer to update July 2, 2020 and July 6, 2020 for additional information.

Updates

November 14, 2019

For somewhat reason, updating the Nuget packages to version 8.0.18 brings back the error, so we stay with 8.0.17 for now.

November 27, 2019

I have a bit of time to play so I checked if the new version really doesn't work. After upgrading it from 8.0.17 to 8.0.18, it truly doesn't work. The following are the error messages and stack traces 3 layer deep exception:

Top level exception
"The provider did not return a ProviderManifestToken string."
   at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)    at MySql.Data.EntityFramework.MySqlManifestTokenResolver.ResolveManifestToken(DbConnection connection)    at System.Data.Entity.Utilities.DbConnectionExtensions.GetProviderInfo(DbConnection connection, DbProviderManifest& providerManifest)    at System.Data.Entity.DbModelBuilder.Build(DbConnection providerConnection)    at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)    at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)    at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()    at System.Data.Entity.Internal.InternalContext.Initialize()    at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)    at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()    at System.Data.Entity.Internal.Linq.InternalSet`1.AsNoTracking()    at System.Data.Entity.Infrastructure.DbQuery`1.AsNoTracking()    at ...
 
 First inner exception
"Unable to connect to any of the specified MySQL hosts."
   at MySql.Data.MySqlClient.NativeDriver.Open()    at MySql.Data.MySqlClient.Driver.Open()    at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings)    at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection()    at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection()    at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()    at MySql.Data.MySqlClient.MySqlPool.GetConnection()    at MySql.Data.MySqlClient.MySqlConnection.Open()    at MySql.Data.MySqlClient.MySqlProviderServices.GetDbProviderManifestToken(DbConnection connection)    at System.Data.Entity.Core.Common.DbProviderServices.GetProviderManifestToken(DbConnection connection)
 
Last inner exception
"Sequence contains more than one matching element"
   at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable`1 source, Func`2 predicate)    at MySql.Data.Common.StreamCreator.GetTcpStream(MySqlConnectionStringBuilder settings)    at MySql.Data.Common.StreamCreator.GetStream(MySqlConnectionStringBuilder settings)    at MySql.Data.MySqlClient.NativeDriver.Open()

Searching online, I found the following thread:

https://forums.mysql.com/read.php?38,678859,678859#msg-678859

which leads to the following bug report:

https://bugs.mysql.com/bug.php?id=97448

And eventually the actual code change:

https://github.com/mysql/mysql-connector-net/commit/9bc44843fda0c2e4aed1e22cc00c1221d17dc00b#diff-7440e953b4e85502ea58c60b17f249ee

For now, we still stick with 8.0.17 until further fix.

June 25, 2020

Actually from the last update until now, we still experience intermittent issues with the error. So, I did few more testing. In my case, I took the following steps to get it completely error free. Probably some steps are not necessary but I haven't had time to test what is actually necessary.

Step 1 (update 7/2/2020, the function somehow is not called)
Create custom DbExecutionStrategy. Mine is actually very simple. All I did is retry only when the error message contains "ProviderManifestToken". I found out MySqlExecutionStrategy that comes with the Nuget package doesn't work for my case.
Protected Overrides Function ShouldRetryOn(exception As Exception) As Boolean
    Return exception IsNot Nothing AndAlso exception.Message.Contains("ProviderManifestToken")
End Function

Step 2
Create a custom DbConfiguration. This is where we can set our custom DbExecutionStrategy. My custom class derives from MySqlEFConfiguration to get all the preset goodness.
Public Class MyCustomDbConfiguration
        Inherits MySqlEFConfiguration

    Sub New()
        MyBase.New()
        SetExecutionStrategy(MySqlProviderInvariantName.ProviderName, Function() New MyCustomDbExecutionStrategy())
    End Sub

End Class

Couple of things to watch out for:

Step 3
There are 3 different ways to apply a DbConfiguration according to the MySQL Connector documentationhttps://dev.mysql.com/doc/connector-net/en/connector-net-entityframework60.html

  1. Adding the DbConfigurationTypeAttribute on the context class
  2. Calling DbConfiguration.SetConfiguration(new MySqlEFConfiguration()) at the application start up
  3. Set the DbConfiguration type in the configuration file.
What I didn't know is which one takes precedence over which. I found out later that the one in configuration file will take precedence over code-based:


In my case, I need the DbContext to default to use MySqlEFConfiguration and overwrite as necessary. So for those applications that need to use the custom DbConfiguration, I added the codeConfigurationType attribute in the config file (app.config/web.config):
<entityFramework codeConfigurationType="namespace.MyCustomDbConfiguration, assembly">

Step 4
On my applications that has the error, the default connection factory was set to LocalDbConnectionFactory. So, following MySQL Connector documentation, I set it to the following under the <entityFramework> tag:
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/>
I found out later that this step might not be necessary as it will only be used when there is no connection string, but I leave it that way since it doesn't hurt.



Step 5
The server that hosted my problematic applications might not have MySql connector installed, so according to the MySQL Connector documentation, I should have added the following entry in the config file:
<system.data>
   <DbProviderFactories>
     <remove invariant="MySql.Data.MySqlClient" />
     <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" 
          type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=8.0.17.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />
   </DbProviderFactories>
</system.data>
Watch out for the version number. It needs to match the MySql.Data.dll assembly version.

So far, the error has not re-appeared in my case. Also, there is a new version 8.0.20 Nuget packages as of this update. I haven't tested it extensively so I can't vouch for its compatibility for now. However, I might write an update once I am certain it doesn't cause issue in our applications.

July 2, 2020

The steps on update June 25, 2020 was not working somehow. When we have a lot of processes hitting the database, the error message returns. I did a quick check and found out that the ShouldRetryOn function was not called. I ended up manually calling the execution strategy.


Dim executionStrategy As New MyCustomDbExecutionStrategy()
executionStrategy.Execute(
    Sub()
        Using dbContext = New MyDbContext()
        ...
        End Using
    End Sub)

On the Nuget version, I found out MySQL.Data and MySQL.Data.EntityFramework version 8.0.20 can connect to Aurora Serverless just fine.


After diving deeper into the code, I had to make a few adjustment and finally managed to ensure that the exception was properly handled. 

First, I reanalyzed the exception details and found out the inner exception is slightly different than the one specified in update November 27, 2019 with the following message:

Authentication to host '...' for user '...' using method 'mysql_native_password' failed with message: Reading from the stream has failed

Second, by the time the exception reaches ShouldRetryOn method, it has been unwrapped.


Third, I have to update my ShouldRetryOn to check for the error message above instead of checking for "ProviderManifestToken" string since it is the inner exception will be passed to ShouldRetryOn. In my case, I prefer to check for "Reading from the stream has failed" string with hope to capture broader errors.

Protected Overrides Function ShouldRetryOn(exception As Exception) As Boolean
    Return exception IsNot Nothing AndAlso exception.Message.Contains("Reading from the stream has failed")")
End Function
Looking into the log file of my application, it finally retries fine and the application ran without issue.

Wednesday, August 21, 2019

OpenVPN Client Save Connection (IP Address)

When I first used OpenVPN client, it was set up for me so I'm missing out on some configuration know how.

Problem

I need to set up OpenVPN on a new computer and I need to save a connection so I can quickly connect to it the next time I log on. In this case, I'm using a v2.x.x OpenVPN client and I can't seem to figure out how to do that.

Solution

It turns out that I have to be disconnected from all connections and then select Import > From server.... Then I can enter my connection information and it will be saved and easily accessible just by hovering over it and select Connect...

Wednesday, August 7, 2019

Refresh System Environment Variables for IIS and Visual Studio

Environment variables can sometimes be a pain to deal with. Since environment variables are often cached or loaded only once, a change might not be immediately reflected in the application that we intend to apply them to.

Problem

 In my case, I need to debug our ASP.NET application and need the new environment variables. 

  • Restarting the Visual Studio itself was not enough. 
  • I tried to kill the worker process and that doesn't help either. 

Solution

At the end, I tried one thing that works which I got from a forum, i.e., enter the following command on command prompt or PowerShell run in admin mode:

iisreset

Tuesday, August 6, 2019

A2 Hosting New Website ASP.NET Default Page Not Shown

This might affect other hosting too, but it just happened that I bumped into it in my A2 hosting account. Basically I created a new website and upload the files. I had the domain name servers updated. Everything looks good. But for somewhat reason, my default page is not shown by default.

I checked the DNS propagations and it was done. I try visiting one of the pages in my website and it works great. But somehow when entering only the domain name, it doesn't bring up the default page. After several hours, I figured out that there is index.html that was put when the directory was setup. Renaming it to something other than list of default documents fix the issue.

Wednesday, June 19, 2019

AWS Code Deploy Error: Make sure your AppSpec file specifies "0.0" as the version

I got this error when attempting to deploy using AWS Code Deploy. Checking the appspec.yml, it does have: version: 0.0. One of the suggestions in StackOverflow was the line ending has to Linux. However that did not help in my case. Since I'm deploying to Windows, the line ending has to be Windows.

After couple trial and error. I found out that Visual Studio save my appspec.yml with UTF-8 encoding, so I proceed to change it to "Western European (Windows) - Codepage 1252" encoding and code deploy works flawlessly.

To change the encoding, I use the following steps in VS2017:
1. Select the file in Solution Explorer.
2. Click File menu on Visual Studio
3. Select Save <filename> As...
4. On the pop up, click the tiny arrow next to the Save button
5. Select Save with Encoding...
6. I select Western European (Windows) - Codepage 1252 for the Encoding and Current Setting for the Line endings.


Monday, June 10, 2019

VB.NET Exit Sub Finally

I have a recurring VB.NET application that will start every 15 minutes. However, as a precaution, the next scheduled instance of the application will immediately exit if the previous instance is still running.

To keep track of the status of the application, I put a code in the finally block that will update the status to stopped and save it to the database.

I noticed that somehow the status of the application was stopped but the application still running in the task manager. There is no background worker so it should exit when the status is updated. It turns out that the subsequent instance update the status when it exited due to finally block is always executed even on "Exit Sub"

Tuesday, May 14, 2019

AWS Aurora "Reading from the stream has failed" Error

We had problem with Aurora SQL throwing error when it is in sleep (pause) mode. By default, it is set to sleep when idle for 5 minutes. After few attempts, we managed to extend the timeout which is command timeout (not to be confused with connection timeout) to 60s in our case to prevent the error from happening. The timeout can be set in connection string:

Server=server;Database=database;Uid=username;Pwd=password;Default Command Timeout=60

Reference:

Update 12/3/2019
The above didn't work somehow on our ASP.NET application that used EntityFramework, so we have to specify it in our ApplicationDbContext constructor and increase it to 5 minutes (300s). The following is the VB.NET version:


Public Sub New(existingConnection As Common.DbConnection, contextOwnsConnection As Boolean)
MyBase.New(existingConnection, contextOwnsConnection)
Database.CommandTimeout = 300
End Sub

Saturday, May 11, 2019

Xamarin "java.exe exited with code 2" Error

Bumped into the following error  "java.exe exited with code 2" when building Xamarin app today. The only thing change is I added a Syncfusion NuGet package. I managed to solve it by enabling MultiDex.

Reference:

Friday, April 5, 2019

Model Binding Issue ASP.NET Core in Ubuntu using Postman

I spent a fair amount of time trying to troubleshoot my ASP.NET Core web server in Ubuntu. The issue starts when I noticed a failed model binding in Ubuntu using HTTP PUT method when it works locally on my Window machine. I also found out that it binds properly when I used HTTPS compared to HTTP.

Looking into the server, I have configured Nginx as reverse proxy server which send a 301 Redirect to HTTPS when the request is made using HTTP. I can't find any issue on the web application itself, Nginx, so I decided to check Postman which I used to generate the request.

I found out that by default, Postman always follows redirect. There is nothing wrong with that, except seems like the data is lost during redirect. Eventually I found out that, 301 is meant to be used with GET and thus any POST/PUT data will be scrapped during redirect. Hence, it is the correct logic all along.

Saturday, March 30, 2019

Method not found System.Net.Http.HttpContentExtensions.ReadAsAsync

Bumped into this error when moving my web app to another server. It happened to me before but this time the cause is different. So two ways that worked for me:

1. Install package Microsoft.AspNet.WebApi.Client. This will provide access to HttpFormatting.dll which actually contains the ReadAsAsync method and fixed the issue for me before.

2. I found out that my System.Net.Http was not referenced properly because it depends on the dll installed in the machine. So, installing System.Net.Http NuGet package fix the current issue for me.

Friday, March 29, 2019

Where is My Environment Variables? Journey to Linux Service

Ok, I had a .NET Core Web App running in Ubuntu behind Nginx. Everything else is fine except I can't retrieve the value of the environment variables that I put in /etc/environment.

After hours of googling, turns out systemd service strips all out except some variables. Two ways to fix this:

1. Put the environment variable in the .service config file

[Service]
Environment=MY_ENV_VAR=thevalue

2. Include /etc/environment in the service. (I don't think this is a good idea, especially for my use case).

[Service]
EnvironmentFile=/etc/environment


Thursday, March 21, 2019

AWS SSM Linux Shell Script Closing Paren Expected Error

I ran my scripts through AWS SSM and received the "closing paren expected" error message. Quick check on my code, I was missing items in two different situations:

1. I was missing closing parentheses \), so adding it solves the issue. My code was like:

if [ \( <expr> ]; then <do this>; fi

2. My closing parentheses was not prefixed by space, so adding a space fixed it. It was like:

if [ \( <expr>\) ]; then <do this>; fi

Linux Script Conditional Conditions

Like most people, I guess, I came from Windows background. Just recently, I have projects exploring multiple flavors of Linux and spending a lot of time to understand how conditions work in bash and/or shell script in Linux. And then my code didn't work and that took me on a journey.

Long time ago, I tried to do something as simple as the following:

if (<expr1> or <expr2>) and (<expr3> or <expr4>) then <do this> fi

But things get complicated as the expressions involve which and grep commands.

For example, I'm checking if any python is installed, so my first attempt was

if [ "`which python`" = "" -a "`which python3`" = "" ]; then echo "no python"; fi

then I realize that in RedHat, if there is no python installed, it will return a string containing "no python" instead of empty string, so my code becomes

if [ \( "`which python`" = "" -o "`which python | grep 'no python'`" = "" \) -a \( "`which python3`" = "" -o "`which python3 | grep 'no python3'`" = "" \) ]; then 

     echo "no python"; 

fi

Well, it didn't work. Scrutinizing it a bit more. I found out that when there is no python, grep doesn't return empty string, but instead a failure code, so that turns my code into:

if [ \( "`which python`" = "" -o "`which python | grep 'no python'`" \) -a \( "`which python3`" = "" -o "`which python3 | grep 'no python3'`" \) ]; then 

     echo "no python"; 

fi


Which seems to work so far, but for consistency, I prefer to use the flag -z to check for empty string and -n to check for non empty string, so the code becomes

if [ \( -z "`which python`" -o -n "`which python | grep 'no python'`" \) -a \( -z "`which python3`"  -o -n "`which python3 | grep 'no python3'`" \) ]; then 

     echo "no python"; 

fi

Wednesday, February 27, 2019

LZMA SDK Compress Decompress

7z is one of the best if not the best file compression available. Best of all, it is open source. The engine behind it is the LZMA compression method. I was integrating the sdk (https://www.7-zip.org/sdk.html) in my project, but however, can't get a quick start on the compress decompress process. After searching the internet, I figured out on a surface level how it all works. Partially thanks to the question in https://stackoverflow.com/questions/7646328/how-to-use-the-7z-sdk-to-compress-and-decompress-a-file. So, below, I write down my basic understanding.

Compress

Basically, the compressed file will contain 3 things with the first 2 are metadata:

  1. The first 5 bytes are compression properties
  2. The next 8 bytes are file size before compression
  3. The compressed bytes

var encoder = New Encoder();
encoder.WriteCoderProperties(outStream); // Write properties
encoder.Write(BitConverter.GetBytes(inputFileSize), 0, 8); // Write uncompressed file size
encoder.Code(inStream, outSteam, inStream.Length, -1, null); // Actual compress

Decompress

To decompress the file, the metadata needs to be provided to the decoder. My code initially threw an error because there is no metadata.


var properties = new byte[5];
inStream.Read(properties, 0, 5); // Read properties

var fileSizeBytes = new byte[8];
inStream.Read(fileSizeBytes, 0, 8); // Read uncompressed file size
var fileSize = BitConverter.ToInt64(fileSizeBytes, 0);

var decoder = New Decoder();
decoder.SetDecoderProperties(properties); // Provide the properties to decoder
decoder.Code(inStream, outStream, inStream.Length, fileSize, null); // Actual decompress

Friday, February 8, 2019

Read-only File System Error in Linux

I was moving the content of CentOS boot drive to a new hard drive. CentOS has MBR partition with xfs file system. It worked great, boot fine, but when I tried to do yum install, it barked that it can't do the install because the file system is read-only.

After a decent amount of research, I found out that the problem lies on the /etc/fstab. Because it is new hard drive, the UUID is different and grub2-mkconfig used the new UUID to configure the grub.cfg. However, when it is booted, it checked the /etc/fstab and found the discrepancy. Once I changed the /etc/fstab to reflect the new UUID, the error went away.

Understanding AWS Security Group

We were playing with AWS Aurora Serverless. After figuring out how to configure and start the database cluster, we were having trouble connecting to it from our EC2 instance. Few hours later, I tried tracing what was going on with Flow Logs in the subnet. We realized it was a network and/or security issue. Checking all possible connections and security, we think everything has been configured correctly. But only after trial and error, we found out that our understanding of security group was incorrect.

Due to AWS security group being promoted as stateful, we understand it as if we specify an entry in Inbound tab, we don't need to specify it in Outbound. Sadly, that is not what stateful means. Each entry specifies the allowed origin of the network request and the response will be automatically allowed. For example, if we allow in Inbound only, a request can come from outside and allowed to the EC2 instance and out, but a request from the instance won't be allowed to go out of the instance. And that is precisely what our problem is, we have an entry in the Inbound tab, but we try to connect from inside the EC2 instance, but was rejected because we don't allow the connection on the Outbound tab. As soon as we allow the connection on the Outbound tab, the problem is fixed.

Thursday, January 17, 2019

Troubleshooting AWS Instance Profile, Role, and SSM Agent

During some AWS troubleshooting session, I happened to notice that there is a possibility of stale role attached to EC2. 

My scenario is as follow: We launched a new EC2 and by default no role attached to it. Then we programmatically create a role, let's call it EC2Role which we then associate it with a new Instance Profile. We then attach the Instance Role to our new EC2. In our case, the EC2Role allows SSM Agent to have permission to run commands.

For somewhat reason, we decided to delete the EC2Role and again programmatically recreate a new role with the same name and associate it with a new Instance Profile. We noticed that when we don't detach the old role (which has the same name with the new one) from the EC2, the old role will still be attached to the EC2 although the old role itself has been deleted. Hence, we were confused on why the EC2 which has the right role attached to it will not run command sent by SSM. The SSM Agent log keeps saying the token is invalid.

I did couple of troubleshooting steps. First, I restarted the SSM Agent and that didn't solve the problem. Second, in a different instance with the same problem, I detached and reattached the role and that didn't work either. Third, I combined previous two steps on a single instance, so I detached and reattached the role then restarted the agent and it works afterwards.




AWS Systems Manager (SSM) Run Command Troubleshooting

I have been working with AWS SSM for couple of months, but I found the troubleshooting document on their website lacks straightforward answers. So I provide the problems that I encountered and the solution based on my experience.

Problem #1: The instance is not visible in AWS Systems Manager Console although documentation says the agent has been installed by default.

Problem #2: The instance is visible, but "Run Command" took too long and even timed out.

Solution:
  1. First thing I would check is whether the instance has a role attached to it.
  2. If so, make sure the role has AmazonEC2RoleforSSM policy attached to it since permission is required for the agent to do health check.
  3. If after all the above has been confirmed, check if the latest SSM agent has been installed and running.
  4. If SSM agent is at the latest and running, check if it is hibernating. The hibernate logic has exponential backoff, so it might not respond for a long time.
  5. If it is hibernating, we can simply restart the agent.
    • On Windows, we can run Restart-Service AmazonSSMAgent PowerShell command.
    • On Linux, we can run sudo restart amazon-ssm-agent shell command.
  6. If all the above fails, it is time to get into the log files.
    • On Windows:
      • %PROGRAMDATA%\Amazon\SSM\Logs\amazon-ssm-agent.log
      • %PROGRAMDATA%\Amazon\SSM\Logs\errors.log
    • On Linux:
      • /var/log/amazon/ssm/amazon-ssm-agent.log
      • /var/log/amazon/ssm/errors.log
  7. If log files doesn't give enough information, we can enable debug logging which will give more information. This requires quite a number of steps, so refer to the reference link below.
Reference