European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: .NET Core Integrating FullCalendar in .NET Core App with JavaScript

clock May 28, 2024 08:06 by author Peter

In order to improve user experience, interactive and user-friendly interface design is essential in modern web development. The integration of dynamic calendars for planning, scheduling, and event management is one typical requirement. To do this, "Integrating FullCalendar in.NET Core Applications with JavaScript" is the best resource. A feature-rich calendar interface may be accessed through the sophisticated JavaScript library FullCalendar, and scalable web applications can be built with a solid backend architecture provided by.NET Core.

From basic setup to sophisticated customisation, this tutorial will lead you through the process of incorporating FullCalendar into your.NET Core application. You will discover how to organize events, make responsive and interactive calendars, and alter the calendar's look to suit your own requirements using JavaScript. Regardless of the complexity of your event management system or scheduling tool, this article will provide you with the knowledge and abilities to integrate FullCalendar with.NET Core with ease, giving your web application a polished and functional calendar solution.

Step 1. Create the calendar view
Create a View for the Calendar
Create a new Razor view named Calendar.cshtml in the Views/Home directory and include the FullCalendar setup.

Initialize the JS and CSS file as the below attachment.
<div class="col-lg-5 ">
    <div class="w-100 m-t-6 task-calendar">
        <div class="card mb-0">
            <div class="card-header">
                <div>
                    <h5>Task Calendar</h5>
                    <span class="d-inline-block calender-date"></span>
                </div>
                <div>

                    <!-- Status badges will be dynamically appended here -->
                </div>
            </div>


            <div class="card-body p-3">
                <div class="table-scrol">
                    <table class="table table-bordered mb-0 tblTaskDetails">
                        <thead>
                            <tr>
                                <th>Sl#</th>
                                <th>Activity</th>
                                <th>Region</th>
                                <th>Mines</th>
                            </tr>
                        </thead>
                        <tbody>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>


Step 2. Write the Javascript code
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function () {
    var calendarEl = document.getElementById('calendar');

    var calendar = new FullCalendar.Calendar(calendarEl, {
        initialView: 'dayGridMonth',
        headerToolbar: {
            left: 'prev,next today',
            center: 'title',
            right: 'dayGridMonth,timeGridWeek,timeGridDay'
        },
        events: function (fetchInfo, successCallback, failureCallback) {
            $.ajax({
                url:"@Url.Action("FetchCalenderData", "User")",
                method: 'GET',
                dataType: 'json',
                success: function (response) {
                    if (response.status === "Successful") {
                        // Aggregate events by date and status
                        var aggregatedEvents = {};
                        response.data.forEach(function (item) {
                            var date = item.actionDate;
                            var status = item.actionStatus;

                            if (!aggregatedEvents[date]) {
                                aggregatedEvents[date] = {};
                            }
                            if (!aggregatedEvents[date][status]) {
                                aggregatedEvents[date][status] = 0;
                            }
                            aggregatedEvents[date][status]++;
                        });

                        // Transform aggregated data into FullCalendar event format
                        var events = [];
                        for (var date in aggregatedEvents) {
                            for (var status in aggregatedEvents[date]) {
                                events.push({
                                    title: status + ' (' + aggregatedEvents[date][status] + ')',
                                    start: date,
                                    extendedProps: {
                                        status: status,
                                        statusCount: aggregatedEvents[date][status]
                                    }
                                });
                            }
                        }

                        successCallback(events);
                    } else {
                        console.log('Error: Data status is not successful');
                        failureCallback();
                    }
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    console.log('Error: ' + textStatus);
                    failureCallback();
                }
            });
        },
        eventClick: function (info) {
            var status = info.event.extendedProps.status;
            var clickedDate = info.event.start;

            /*Date Formating For Send To DB for Filter*/
            const CurrentDateForDB = new Date(clickedDate);
            const year = CurrentDateForDB.getFullYear();
            const month = String(CurrentDateForDB.getMonth() + 1).padStart(2, '0');
            const day = String(CurrentDateForDB.getDate()).padStart(2, '0');
            const ClickedformattedDate = `${year}-${month}-${day}`;
            /*END*/

            var options = { day: 'numeric', month: 'short', year: 'numeric' };
            var formattedDate = clickedDate.toLocaleDateString('en-US', options);
            // Make an AJAX call with the status name
            $.ajax({
              url: "@Url.Action("FetchActivityDtlsByStatus", "User")",
                method: 'GET',
                data: { ActivityStatus: status, ActivityDate: ClickedformattedDate },
                success: function (response) {
                    console.log(response);

                    if (response.status === "Successful") {
                        var tbody = $('.tblTaskDetails tbody');
                        tbody.empty(); // Clear existing rows

                        response.data.forEach(function (item, index) {
                            var row = '<tr>' +
                                '<td>' + (index + 1) + '</td>' +
                                '<td>' + item.activiTyName + '</td>' +
                                '<td>' + item.regionName + '</td>' +
                                '<td>' + item.minesName + '</td>' +
                                '</tr>';
                            tbody.append(row);
                        });


                        if (clickedDate) {
                            $('.calender-date').text(formattedDate);
                        } else {
                            $('.calender-date').text('No Date Clicked');
                        }

                        // Clear existing status badges
                        $('.card-header div:nth-child(2)').empty();

                        // Display all unique statuses
                        var statusColors = {
                            'Approved': 'text-bg-success',
                            'Open': 'text-bg-primary',
                            'InProgress': 'text-bg-warning'
                        };

                        var uniqueStatuses = [...new Set(response.data.map(item => item.activityStatus))];
                        uniqueStatuses.forEach(function (status) {
                            var badgeClass = statusColors[status] || 'text-bg-secondary'; // Default color if status is not mapped
                            var statusBadge = '<h5>Status</h5><span class="badge ' + badgeClass + ' calender-status">' + status + '</span>';
                            $('.card-header div:nth-child(2)').append(statusBadge);
                        });

                    } else {
                        alert('Error: Data status is not successful');
                    }
                },
                error: function (jqXHR, textStatus, errorThrown) {
                    console.log('Error: ' + textStatus);
                }
            });


        }
    });

    calendar.render();
});
</script>

Step 3. Write the Controller code
#region------------------------Calendar View-------------------------------------
/// <summary>
/// CalenderView Page
/// </summary>
/// <returns></returns>
[HttpGet]
public IActionResult CalenderView()
{
    return View();
}

/// <summary>
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> FetchCalenderData()
{
    FetchCalendarData fcdaTa = new FetchCalendarData();
    try
    {
        using (var httpClient = new HttpClient(_clientHandler))
        {
            var response = await httpClient.PostAsJsonAsync(_options._apiRootURL + "User/GetCalendarData", fcdaTa);
            if (response.StatusCode.ToString() != "ServiceUnavailable")
            {
                string apiResponse = await response.Content.ReadAsStringAsync();
               var  ResultData = JsonConvert.DeserializeObject<FetchCalendarDataInfo>(apiResponse);
                return Json(ResultData);
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return Json("");
}


/// <summary>
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> FetchActivityDtlsByStatus(FetchActivityDetailsData fcdaTa)
{
    try
    {
        using (var httpClient = new HttpClient(_clientHandler))
        {
            var response = await httpClient.PostAsJsonAsync(_options._apiRootURL + "User/GetActivityDtlsByStatus", fcdaTa);
            if (response.StatusCode.ToString() != "ServiceUnavailable")
            {
                string apiResponse = await response.Content.ReadAsStringAsync();
                var ResultData = JsonConvert.DeserializeObject<FetchActivityDetailsDataInfo>(apiResponse);
                return Json(ResultData);
            }
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
    return Json("");
}
#endregion-----------------------------------------------------------------------


Step 4. Page load JSON response
{
    "status": "Successful",
    "data": [
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Open"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Open"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "InProgress"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Approved"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Open"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "InProgress"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Approved"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Open"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "InProgress"
        },
        {
            "actionDate": "2024-05-23",
            "actionStatus": "Approved"
        },
        {
            "actionDate": "2024-05-24",
            "actionStatus": "InProgress"
        },
        {
            "actionDate": "2024-05-27",
            "actionStatus": "InProgress"
        },
        {
            "actionDate": "2024-05-27",
            "actionStatus": "Open"
        },
        {
            "actionDate": "2024-05-27",
            "actionStatus": "InProgress"
        },
        {
            "actionDate": "2024-05-27",
            "actionStatus": "Approved"
        }
    ]
}

JSON
Step 5. Button click JSON response

{
    "status": "Successful",
    "data": [
        {
            "activityStatus": "Open",
            "activiTyName": "Promotion Activities",
            "regionName": "Manchester",
            "minesName": "
Manchester",
            "activityDate": "2024-05-23"
        },
        {
            "activityStatus": "Open",
            "activiTyName": "Promotion Activities",
            "regionName": "Leeds",
            "minesName": "
Leeds",
            "activityDate": "2024-05-23"
        },
        {
            "activityStatus": "Open",
            "activiTyName": "Content Creation",
            "regionName": "",
            "minesName": "",
            "activityDate": "2024-05-23"
        },
        {
            "activityStatus": "Open",
            "activiTyName": "Promotion Activities",
            "regionName": "London",
            "minesName": "
London",
            "activityDate": "2024-05-23"
        }
    ]
}


Conclusion
Using JavaScript to integrate FullCalendar into a.NET Core application provides a strong way to create dynamic and interactive calendar interfaces. You've successfully installed FullCalendar in your.NET Core project, setup the required dependencies, made a view to show the calendar, and put a controller action in place to serve events by following the instructions in this guide.You can now use FullCalendar's features to create powerful scheduling tools, event management systems, or any other application that needs calendar capability, once it has been integrated into your program. Additionally, you are able to alter the calendar's look, functionality, and event handling to meet your own needs.

As you continue to develop your .NET Core application, you can further enhance the integration with FullCalendar by exploring additional plugins, implementing features such as drag-and-drop event creation, integrating with external data sources, or incorporating advanced scheduling functionalities.

Overall, integrating FullCalendar with .NET Core empowers you to create seamless and intuitive user experiences, enhancing the functionality and usability of your web applications.

HostForLIFE ASP.NET Core 8.0.4 Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Effectively Parsing Solutions in.NET 8 with DTE and Microsoft.Build

clock May 21, 2024 08:44 by author Peter

In the context of C#, a solution parser refers to a program or library that can parse and comprehend data from Visual Studio solution (.sln) files and its project (.csproj) files. These parsers enable developers to work with, adjust, and examine a solution's architecture and components, including its projects, dependencies, references, and build settings.

Benefits of a Solution Parser in C#

  • Automated Analysis and Reporting: Solution parsers enable the automated extraction of information regarding the structure, dependencies, and configurations of a solution. This feature proves to be valuable in generating reports on code quality, dependencies, and build status.
  • Dependency Management: Through the parsing of solution and project files, tools can analyze and visualize the dependencies between projects. This capability aids in identifying potential issues like circular dependencies or outdated packages.
  • Build Automation: Integrating solution parsers into build automation scripts allows for dynamic modification of solution and project configurations. This proves to be beneficial in continuous integration (CI) pipelines where different build environments may require different settings.
  • Refactoring Support: Developers can utilize solution parsers to automate refactoring tasks, such as renaming projects, updating namespaces, or restructuring solution folders.
  • Custom Tooling: Solution parsers can be utilized to build custom development tools that cater to specific needs, such as custom linting rules, project templates, or automated code generation.


Popular Parsing Solutions for C#

  • Microsoft Build (MSBuild): Visual Studio and.NET use MSBuild as their build platform. It provides developers with a variety of APIs to load, query, and edit project files. Solution files can be parsed indirectly using these APIs. Microsoft.Build.Evaluation and Microsoft.Build.Locator are the most often utilized namespaces for this kind of work.
  • EnvDTE: An automation model that gives developers a way to communicate with the Visual Studio environment is called the Development Tools Environment. Developers can work with solution and project elements from Visual Studio extensions or automation scripts thanks to this access.
  • NuGet Package Manager: The NuGet Package Manager offers tools such as NuGet.Protocol and NuGet.Packaging, which can be employed to manage dependencies specified in project files. When combined with other libraries, these tools can form an integral part of a comprehensive solution parsing and manipulation toolkit.


Implementation
Step 1. Xaml View
<Window x:Class="SolutionParserExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SolutionParserExample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <GroupBox Header="WithDTE Result[First Approach]" Grid.Row="0">
            <DataGrid x:Name="DataridWithDTE"/>
        </GroupBox>

        <GroupBox Header="WithoutOutDTE Result[Second Approach]" Grid.Row="1">
            <DataGrid x:Name="DataridWithoutDTE"/>
        </GroupBox>

        <GroupBox Header="WithoutOutDTE Result[Third Approach]" Grid.Row="2">
            <DataGrid x:Name="DataridThirdApproach"/>
        </GroupBox>
    </Grid>

</Window>

Code behind(CS file)
using EnvDTE80;
using Microsoft.Build.Construction;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using Window = System.Windows.Window;

namespace SolutionParserExample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Type? s_SolutionParserFromSolutionFile;
        PropertyInfo? s_SolutionParserReader;
        MethodInfo? s_SolutionParserSolution;
        PropertyInfo? s_SolutionParserProjects;
        public List<ProjectSolution> ProjectsList { get; set; }
        ProjectInSolution[] arrayOfProjects = null;

        // Change below path with your solution file
        string solutionFilePath = @"C:\Users\sanjay\Desktop\MediaElementSampleProject (3)\MediaElementSampleProject\MediaElementSampleProject.sln";
        private ObservableCollection<ProjectDetail> _ProjectsListWithoutDTE;

        public ObservableCollection<ProjectDetail> ProjectsListWithoutDTE
        {
            get { return _ProjectsListWithoutDTE; }
            set { _ProjectsListWithoutDTE = value; }
        }

        private ObservableCollection<ProjectDetail> _ProjectsListWithDTE;

        public ObservableCollection<ProjectDetail> ProjectsListWithDTE
        {
            get { return _ProjectsListWithDTE; }
            set { _ProjectsListWithDTE = value; }
        }

        private ObservableCollection<ProjectDetail> _ProjectsListThirdApproachExample;

        public ObservableCollection<ProjectDetail> ProjectsListThirdApproachExample
        {
            get { return _ProjectsListThirdApproachExample; }
            set { _ProjectsListThirdApproachExample = value; }
        }

        public MainWindow()
        {
            InitializeComponent();
            GetProjectDetailsWithDTE(); // First Approach
            GetProjectDetailsWithoutDTE(); // Second Approach
            GetProjectInformationByThirdApproach(); // Third Approach
            DataridWithoutDTE.ItemsSource = ProjectsListWithoutDTE;
            DataridWithDTE.ItemsSource = ProjectsListWithDTE;
            DataridThirdApproach.ItemsSource = ProjectsListThirdApproachExample;
        }

        private void GetProjectInformationByThirdApproach()
        {
            // Load the solution file
            SolutionFile solutionFile = SolutionFile.Parse(solutionFilePath);
            ProjectsListThirdApproachExample = new ObservableCollection<ProjectDetail>();

            // Iterate through each project in the solution
            foreach (var project in solutionFile.ProjectsInOrder)
            {
                string projectName = project.ProjectName;
                string projectRelativePath = project.RelativePath;
                string projectFullPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(solutionFilePath), projectRelativePath);
                string projectGuid = project.ProjectGuid;
                string projectType = project.ProjectType.ToString();

                ProjectsListThirdApproachExample.Add(new ProjectDetail
                {
                    ProjectName = projectName,
                    ProjectGuid = projectGuid,
                    ProjectType = projectType,
                    RelativePath = projectRelativePath,
                });
            }
        }

        private string GetRelativePath(string basePath, string fullPath)
        {
            Uri baseUri = new Uri(basePath + Path.DirectorySeparatorChar);
            Uri fullUri = new Uri(fullPath);
            Uri relativeUri = baseUri.MakeRelativeUri(fullUri);
            string relativePath = Uri.UnescapeDataString(relativeUri.ToString());

            return relativePath.Replace('/', Path.DirectorySeparatorChar);
        }

        private void GetProjectDetailsWithDTE()
        {
            string solutionDirectory = Path.GetDirectoryName(solutionFilePath);
            var dte = GetDTE();
            dte.Solution.Open(solutionFilePath);
            ProjectsListWithDTE = new ObservableCollection<ProjectDetail>();

            foreach (EnvDTE.Project project in dte.Solution.Projects)
            {
                ProjectsListWithDTE.Add(new ProjectDetail
                {
                    ProjectName = project.Name,
                    RelativePath = GetRelativePath(solutionDirectory, project.FullName),
                });
            }
            dte.Solution.Close(false);
        }

        private DTE2 GetDTE()
        {
            Type dteType = Type.GetTypeFromProgID("VisualStudio.DTE.17.0", true);
            object obj = Activator.CreateInstance(dteType, true);
            return (DTE2)obj;
        }

        private void GetProjectDetailsWithoutDTE()
        {
            s_SolutionParserFromSolutionFile = Type.GetType("Microsoft.Build.Construction.SolutionFile, Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, true);

            if (s_SolutionParserFromSolutionFile != null)
            {
                s_SolutionParserReader = s_SolutionParserFromSolutionFile.GetProperty("SolutionReader", BindingFlags.NonPublic | BindingFlags.Instance);
                s_SolutionParserProjects = s_SolutionParserFromSolutionFile.GetProperty("ProjectsInOrder", BindingFlags.Public | BindingFlags.Instance);
                s_SolutionParserSolution = s_SolutionParserFromSolutionFile.GetMethod("ParseSolution", BindingFlags.NonPublic | BindingFlags.Instance);
            }

            if (s_SolutionParserFromSolutionFile != null)
            {
                var solutionResultParser = s_SolutionParserFromSolutionFile.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic).First().Invoke(null);

                using (var streamReader = new StreamReader(solutionFilePath))
                {
                    s_SolutionParserReader.SetValue(solutionResultParser, streamReader, null);
                    s_SolutionParserSolution.Invoke(solutionResultParser, null);
                }

                var projects = new List<ProjectSolution>();
                var projectsobj = s_SolutionParserProjects.GetValue(solutionResultParser, null) as IReadOnlyList<ProjectInSolution>;

                if (projectsobj != null)
                {
                    arrayOfProjects = projectsobj.ToArray();
                }

                for (int i = 0; i < arrayOfProjects.Length; i++)
                {
                    projects.Add(new ProjectSolution(arrayOfProjects.GetValue(i)));
                }

                this.ProjectsList = projects;
                ProjectsListWithoutDTE = new ObservableCollection<ProjectDetail>();

                foreach (var item in ProjectsList)
                {
                    ProjectsListWithoutDTE.Add(new ProjectDetail
                    {
                        ProjectName = item.ProjectName,
                        ProjectGuid = item.ProjectGuid,
                        ProjectType = item.ProjectType,
                        RelativePath = item.RelativePath,
                    });
                }
            }
        }
    }

    public class ProjectSolution
    {
        static readonly PropertyInfo? s_ProjectName;
        static readonly PropertyInfo? s_RelativePath;
        static readonly PropertyInfo? s_ProjectGuid;
        static readonly PropertyInfo? s_ProjectType;

        static ProjectSolution()
        {
            Type? ProjectInSolution = Type.GetType("Microsoft.Build.Construction.ProjectInSolution, Microsoft.Build, Version=15.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", false, true);

            if (ProjectInSolution != null)
            {
                s_ProjectName = ProjectInSolution.GetProperty("ProjectName", BindingFlags.Public | BindingFlags.Instance);
                s_RelativePath = ProjectInSolution.GetProperty("RelativePath", BindingFlags.Public | BindingFlags.Instance);
                s_ProjectGuid = ProjectInSolution.GetProperty("ProjectGuid", BindingFlags.Public | BindingFlags.Instance);
                s_ProjectType = ProjectInSolution.GetProperty("ProjectType", BindingFlags.Public | BindingFlags.Instance);
            }
        }

        public string ProjectName { get; private set; }
        public string RelativePath { get; private set; }
        public string ProjectGuid { get; private set; }
        public string ProjectType { get; private set; }

        public ProjectSolution(object solutionProject)
        {
            this.ProjectName = (s_ProjectName == null ? "" : s_ProjectName.GetValue(solutionProject, null) as string);
            this.RelativePath = (s_RelativePath == null ? "" : s_RelativePath.GetValue(solutionProject, null) as string);
            this.ProjectGuid = (s_ProjectGuid == null ? "" : s_ProjectGuid.GetValue(solutionProject, null) as string);
            this.ProjectType = (s_ProjectType == null ? "" : s_ProjectType.GetValue(solutionProject, null).ToString());
        }
    }
}


Step 2. Result View

HostForLIFE ASP.NET Core 8.0.4 Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Recognizing OLTP versus OLAP Techniques

clock May 16, 2024 09:04 by author Peter

Two key methodologies stand out in the field of data management and analytics: online transaction processing, or OLTP, and online analytical processing, or OLAP. These approaches address various facets of data processing, storage, and analysis and have diverse functions. It is essential to comprehend the distinctions between OLTP and OLAP in order to construct efficient data management systems and make wise decisions across a range of industries, including e-commerce and banking.

1. History and Evolution
OLTP

OLTP traces its origins back to the 1960s with the emergence of early database management systems (DBMS). It primarily focuses on managing transaction-oriented tasks, such as recording sales, processing orders, and updating inventory levels in real time. OLTP systems are designed for high concurrency and rapid response times, ensuring efficient handling of numerous short online transactions.

OLAP
On the other hand, OLAP gained prominence in the late 1980s and early 1990s as organizations recognized the need for advanced analytics and decision support systems. OLAP systems are optimized for complex queries, ad-hoc reporting, and multidimensional analysis. They provide a consolidated view of data from various sources, enabling users to gain insights through interactive analysis and reporting.

2. Purpose and Need

OLTP: The primary goal of OLTP systems is to support the day-to-day transactional operations of an organization. These transactions are typically characterized by short response times and high throughput. For example, when a customer places an order on an e-commerce website, the OLTP system ensures that the order is processed promptly, inventory is updated, and the transaction is recorded in the database.

OLAP: In contrast, OLAP systems are designed to facilitate decision-making by providing a comprehensive view of historical and aggregated data. They enable users to analyze trends, identify patterns, and make informed strategic decisions. For instance, a retail company might use OLAP to analyze sales data across different regions, product categories, and time periods to optimize inventory management and marketing strategies.

3. Evolution to Address Modern Challenges

As technology evolves and data volumes continue to grow exponentially, both OLTP and OLAP systems have undergone significant transformations to address modern challenges:

  • Scalability: With the advent of cloud computing and distributed databases, OLTP and OLAP systems have become more scalable and resilient. They can handle massive volumes of data and support high levels of concurrency, ensuring optimal performance even under heavy workloads.
  • Real-time Analytics: The demand for real-time analytics has led to the integration of OLTP and OLAP functionalities in hybrid transactional/analytical processing (HTAP) systems. These systems combine the benefits of both OLTP and OLAP, allowing organizations to perform analytics on live transactional data without the need for separate data warehouses.
  • In-memory Computing: In-memory computing has emerged as a game-changer for both OLTP and OLAP systems, enabling faster data processing and analysis by storing data in memory rather than on disk. This approach significantly reduces latency and enhances overall system performance, making it ideal for time-sensitive applications and interactive analytics.

Demonstration in C#
Below is a simplified C# code snippet demonstrating the difference between OLTP and OLAP queries using a hypothetical e-commerce scenario:
// OLTP Query: Retrieve order details for a specific customer
public Order GetOrderDetails(int customerId)
{
    using (var dbContext = new OLTPDbContext())
    {
        return dbContext.Orders
            .Include(o => o.OrderItems)
            .SingleOrDefault(o => o.CustomerId == customerId);
    }
}

// OLAP Query: Analyze sales data by product category
public Dictionary<string, int> GetSalesByCategory()
{
    using (var dbContext = new OLAPDbContext())
    {
        return dbContext.OrderItems
            .GroupBy(oi => oi.Product.Category)
            .ToDictionary(g => g.Key, g => g.Sum(oi => oi.Quantity));
    }
}


In this example, the OLTP query retrieves order details for a specific customer in real time, while the OLAP query analyzes sales data by product category for strategic decision-making.

OLTP and OLAP practices play complementary roles in modern data management and analytics. By understanding their differences and capabilities, organizations can design robust systems that meet their transactional and analytical needs effectively.

HostForLIFE ASP.NET Core 8.0.4 Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core 8.0.1 Hosting - HostForLIFE :: Putting Role-Based and Policy-Based Authorization into Practice with .NET Core

clock May 7, 2024 09:03 by author Peter

The focus of this essay is on utilizing.NET Core for policy-based authorization. If you want to understand the fundamentals of authorization techniques, please click the link. Let's dissect the essential elements:

Configuring Authentication

  • Initially, configure your application's authentication. By doing this, users' identity and authentication are guaranteed.
  • To handle user logins and token issuance, you will usually employ a third-party authentication provider (such as Microsoft Identity Platform).

Authorization Policies

  • Next, define authorization policies. These policies determine who can access specific parts of your application.
  • Policies can be simple (e.g., “authenticated users only”) or more complex (based on claims, roles, or custom requirements).

Default Policy

  • Create a default policy that applies to all endpoints unless overridden.
  • For example, you might require users to be authenticated and have specific claims (like a preferred username).

Custom Policies

  • Add custom policies for specific scenarios. These allow fine-grained control over access.
  • For instance, you can create policies based on permissions (e.g., “create/edit user” or “view users”).

Permission Requirements

  • Define permission requirements (e.g., PermissionAuthorizationRequirement). These represent specific actions or features.
  • For each requirement, check if the user has the necessary permissions (based on their roles or other criteria).

Role-Based Authorization

  • Optionally, incorporate role-based authorization.
  • Roles group users with similar access levels (e.g., “admin,” “user,” etc.). You can assign roles to users.

Authorization Handlers

  • Implement custom authorization handlers (e.g., AuthorizationHandler).
  • These handlers evaluate whether a user meets the requirements (e.g., has the right permissions or roles).

Controller Actions

  • In your controller actions, apply authorization rules.
  • Use [Authorize] attributes with either policies or roles.

Middleware Result Handling

  • Customize how authorization results are handled (e.g., 401 Unauthorized or 403 Forbidden responses).
  • You can create an AuthorizationMiddlewareResultHandler to manage this behavior

Let's go ahead will the actual coding for your Web API:

Program.cs: User Azure AD authentication as it is. Decide your Permission Keys for Authorization.
Only one policy in the AddPolicy method
//In Program.cs file, add the below code

        var builder = WebApplication.CreateBuilder(args);

        // Authentication using Microsoft Identity Platform
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));

        // Default policy-based authorization
        services.AddAuthorizationCore(options =>
        {
            options.DefaultPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .RequireClaim("preferred_username")
                .RequireScope("user_impersonation")
                .Build();

            options.AddPolicy("Permission1", policy =>
                policy.Requirements.Add(new PermissionAuthorizationRequirement("Permission1")));

            options.AddPolicy("Permission2", policy =>
                policy.Requirements.Add(new PermissionAuthorizationRequirement("Permission2")));
        });

        // Authorization handler
        services.AddScoped<IAuthorizationHandler, AuthorizationHandler>();

        // Middleware result handler for response errors (401 or 403)
        services.AddScoped<IAuthorizationMiddlewareResultHandler, AuthorizationMiddlewareResultHandler>();

        // Other services and configurations...


PermissionAuthorizationRequirement .cs: Just copy and paste the requirement
//Create new PermissionAuthorizationRequirement.cs file for Custom requirement for permission-based authorization
    public class PermissionAuthorizationRequirement : IAuthorizationRequirement
    {
        public PermissionAuthorizationRequirement(string allowedPermission)
        {
            AllowedPermission = allowedPermission;
        }

        public string AllowedPermission { get; }
    }


AuthorizationHandler.cs: (Just copy and paste the code. Make sure to hit the DB call to get the permissions list by using App Manager)
// Custom authorization handler to check user permissions
    public class AuthorizationHandler : AuthorizationHandler<PermissionAuthorizationRequirement>
    {
        // Business layer service for user-related operations
        private readonly IAppManager _appManager;

        public AuthorizationHandler(IAppManager appManager)
        {
            _appManager= appManager;
        }

        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement)
        {
            // Find the preferred_username claim
            var preferredUsernameClaim = context.User.Claims.FirstOrDefault(c => c.Type == "preferred_username");

            if (preferredUsernameClaim is null)
            {
                // User is not authenticated
                context.Fail(new AuthorizationFailureReason(this, "UnAuthenticated"));
                return;
            }

            // Call the business layer method to check if the user exists
            var user = await _appManager.GetUserRolesAndPermissions(preferredUsernameClaim);

            if (user is null || !user.IsActive)
            {
                // User does not exist or is inactive
                context.Fail(new AuthorizationFailureReason(this, "UnAuthenticated"));
                return;
            }

            // Select the list of permissions that the user is assigned
            // Here you will fetch the Permission1 and Permission2
            var userPermissions = user.UserPermissions?.Select(k => k.PermissionKey);

            // Get the current permission key from the controller's action method
            string allowedPermission = requirement.AllowedPermission;


            // Check if the current request carries this permission
            if (userPermissions.Any(permission => permission == allowedPermission))
            {
                // Permission granted
                context.Succeed(requirement);
                return;
            }

            // Permission denied
            context.Fail();
        }
    }


AuthorizationMiddlewareResultHandler.cs: Just copy and paste. No changes are required.

// AuthorizationMiddlewareResultHandler to decide response code (401 or success)
public class AuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler
{
    private readonly ILogger<AuthorizationMiddlewareResultHandler> _logger;
    private readonly Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler _defaultHandler = new();

    public AuthorizationMiddlewareResultHandler(ILogger<AuthorizationMiddlewareResultHandler> logger)
    {
        _logger = logger;
    }

    public async Task HandleAsync(
        RequestDelegate next,
        HttpContext context,
        AuthorizationPolicy policy,
        PolicyAuthorizationResult authorizeResult)
    {
        var authorizationFailureReason = authorizeResult.AuthorizationFailure?.FailureReasons.FirstOrDefault();
        var message = authorizationFailureReason?.Message;

        if (string.Equals(message, "UnAuthenticated", StringComparison.CurrentCultureIgnoreCase))
        {
            // Set response status code to 401 (Unauthorized)
            context.Response.StatusCode = "401";
            _logger.LogInformation("401 failed authentication");
            return;
        }

        // If not unauthorized, continue with default handler
        await _defaultHandler.HandleAsync(next, context, policy, authorizeResult);
    }
}

Controller.cs: Finally, in the dashboard controller, add the attributes [Authorize] and [Policies]. Here you will define Permission1 and Permission2
// Dashboard controller
[Authorize]
[Route("api/[controller]")]
[ApiController]
public class DashboardController : ControllerBase
{
    [HttpGet]
    [Route("get-dashboardDetails")]
    [Authorize(Policy = "Permission1")]
    public async Task GetAllDashboardDetailsAsync()
    {
        // Your logic for fetching all user details
        return await GetAllDashboardDetailsAsync();
    }

    [HttpGet]
    [Route("create-product")]
    [Authorize(Policy = "Permission2")]
    //[Authorize(Policy = nameof(Read string from ENUM))]
    public async Task CreateProductAsync([FromBody] Product product)
    {
        // Your logic for creating a new product
    }
}

Now if you want to combine with Roles based authorization in your Web API code. Follow the below steps or you can avoid moving forward. It is almost the same steps as we did with the policy-based authorization with a small difference that you will figure out in the code.

1. Register the RoleAuthorizationHandler: In your Program.cs file, just add the following line to register the RoleAuthorizationHandler
builder.Services.AddScoped<IAuthorizationHandler, RoleAuthorizationHandler>();

2. RoleAuthorizationHandler: Below is the RoleAuthorizationHandler.cs one that checks whether the user has the required roles. Create one more handler
public class RoleAuthorizationHandler : AuthorizationHandler<RolesAuthorizationRequirement>
{
    private readonly IAppManager _appManager;

    public RoleAuthorizationHandler(IAppManager appManager)
    {
        _appManager= appManager;
    }

    protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement)
    {
        // Find the preferred_username claim
        Claim claim = context.User.Claims.FirstOrDefault(c => c.Type == "preferred_username");

        if (claim is not null)
        {
            // Get user details
            var userRoles = await _appManager.GetUserRolesAndPermissions(claim.Value);

            // Check if the user's roles match the allowed roles
            var roles = requirement.AllowedRoles;
            if (userRoles .Any(x => roles.Contains(x)))
            {
                context.Succeed(requirement); // User has the required roles
            }
            else
            {
                context.Fail(); // User does not have the required roles
                return;
            }
        }
        await Task.CompletedTask;
    }
}


3. Usage in DashboardController: In your DashboardController, you can use both roles and policies for authorization. For example:
[HttpGet]
[Route("get-dashboardDetails")]
[Authorize(Roles = "Super_Admin, Role_Administrator")] // Can have multiple roles. You can choose either Roles or Policy or both
[Authorize(Policy = "Permission1")] // Can have only one policy per action to accept.
public async Task GetAllDashboardDetailsAsync()
{
    // Your logic for fetching all user details
    return await GetAllDashboardDetailsAsync();
}


That's all. Your Web API will work like magic.
Stay tuned for more learning.

HostForLIFE ASP.NET Core 8.0.4 Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in