Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Monday, June 6, 2022

dotnet string compare like a database

Issue

You make a query on a rdbms database that compares strings with case INSENSITIVE rules instead binary comparison (like case insensitive + accent sensitive of Microsoft SQL Server).

Suppose that you have this table (MYDATA)


MYCODE DESCRIPTION
A A-DESCRIPTION
B B-DESCRIPTION
C C-DESCRIPTION
D D-DESCRIPTION
E E-DESCRIPTION

Suppose that you have to query this table based on website query string params, something like this:

https://myexample.com/favourites?first=a&second=b

If you use old-fashion style you can query database directly using SQL query like this:

DECLARE @first NVARCHAR(MAX);
DECLARE @second NVARCHAR(MAX); SET @first= 'a';
SET @second= 'b'; SELECT * FROM MYDATA WHERE MYCODE = @first OR MYCODE = @second;
GO

If you are using Microsoft SQL Server with collation sequence CASE INSENSITIVE and ACCENT SENSITIVE you will have 2 rows

CODE DESCRIPTION
A A-DESCRIPTION
B B-DESCRIPTION

You will have row with code 'A' and row with code 'B' even you were looking for 'a' and 'b' (case insensitive).

If you are using ORM you can query database using expression or linq like this:

IEnumerable<MyEntity> selectedData = dataRepo.Where(myEntity => myEntity.Code == first || myEntity.Code == second).ToList();

Above query returns 2 items (2 items of MyEntity).

Next in your code you need to find separately first and second.
(...remember that first value is 'a' and second value is 'b'.)

You can use this in memory expression:
MyEntity firstData = selectedData.FirstOrDefault(myEntity => myEntity.Code == first);

or this linq:

MyEntity firstData = (from items in selectedData
                         where items.Code == first
                         orderby items.Code
                         select items).FirstOrDefault();

Both solutions return NULL !!!

You have used same variables 'first' or 'second', but RDBMS Microsoft SQL Server works in case insensitive and in memory comparison is done using binary comparison.

Common solution is to use .ToUpper() on both string in every memory comparison. This solution works but: is legacy not flexible and you need to remember this rule.

More flexible and dynamic solution is DevExtremeToys package.
With this package you can add this using:

using DevExtremeToys.StringComparer;

Now you can configure the string comparison behavior in this way:

            CompareSettings.Instance.GetSetting = () =>
            {
                return new Settings()
                {
                    CaseOption = CaseOptions.Insensitive,
                    AccentOption = AccentOptions.Sensitive
                };
            };

Then you can use new string extensions like this:

firstData = selectedData.FirstOrDefault(myEntity => myEntity.Code.EqualsDevEx(first));

or this:

            firstData = (from items in selectedData
                         where items.Code.EqualsDevEx(first)
                         orderby items.Code
                         select items).FirstOrDefault();

With this solution you will have the same behavior between memory and database.

You can configure string comparison rules once, like the previous example, or specifying compare rules in each comparison using overload with compare settings parameter.

You can see more instructions and source code in github repository.

Enjoy

Wednesday, February 10, 2021

Azure IP address list

Are you looking for Azure IP addresses list?

I've published simple API to get all the Azure ip address list, at all, by region or by services.

How to get the ip address list of  a specified Azure Service in a specified Azure region

https://azinfo.azurewebsites.net/api/servicetags/{regionName}/{serviceName}
It's a GET command.
You have to replace {regionname} with a valid region name and {servicename} with a valid service name.
You can get the list of valid values for {regionname} and {servicename} with the API below

How to get valid region names

https://azinfo.azurewebsites.net/api/GetRegionNameList
It's a GET command.
Its return a list of valid region names and a special name "allregions" that you can use to get data for all regions.
If you use "allregions" with the first api above, you'll get all ip list of the specified service at all (not by region).

How to get valid service names

https://azinfo.azurewebsites.net/api/GetServiceNameList
It's a GET command.
Its return a list of valid Azure service names.

How to get the all the ip address list of all Azure Services in a specified Azure region

https://azinfo.azurewebsites.net/api/region/{regionName}
It's a GET command.
Its return a list with all Azure ip in the specified region.
If you use "allregions" as regionName, you'll get all Azure ip list. 


Where I get this data

Microsoft offer two way to find out Azure IP address list. 

One way is to download the weekly JSON file ad parse it like this example.
This file is weekly updated.
It's quite simple download it but you have to schedule the download of the file and you have to parse the file as you need.

Another way is to use "Service Tags - List" API.
To use this api you have to:
  • register Microsoft.Netowork resource provider at subscription level
  • configure a user\principal of the Azure Active Directory 
  • register an application to authenticate and grant access
  • authenticate with this user or principal to have oauth token
at this point you can use the Microsoft api:
https://management.azure.com/subscriptions/{subscriptionId}/providers/Microsoft.Network/locations/{location}/serviceTags?api-version=2020-07-01

Interesting documentations






Please Note

My API are Azure Functions hosted in a Free Plan, so after limited daily period of usage they will be unavailable.