CSharp - Other

Email Notifications System

/// <summary>
/// Notifications system
/// </summary>
/// <returns>Result object</returns>
private Result NotificationsSystem()
{
    // Auxiliary variables
    DataTable _dtRecords;
    Result _Result = new Result();

    // Get results from database
    _dtRecords = GetResults();

    // Check success
    if (_dtRecords != null && _dtRecords.Rows.Count > 0)
    {
        // Load email template file path
        string _strEmailTemplate = LoadEmailTemplate();

        // Check email template path is not null
        if (string.IsNullOrEmpty(_strEmailTemplate))
        {
            // Add error message
            _Result.AddError("Undefined email template!");

            // Return
            return _Result;
        }

        // Check if template file exists
        if (!File.Exists(_strEmailTemplate))
        {
            // Add error message
            _Result.AddError("Email template doesn't exist!");

            // Return
            return _Result;
        }

        // Load excel directory path
        string _strExcelFilesPath = LoadExcelFilesPath();

        // Check if directory exists
        if (!Directory.Exists(Path.GetDirectoryName(_strExcelFilesPath)))
        {
            // Create directory
            Directory.CreateDirectory(Path.GetDirectoryName(_strExcelFilesPath));
        }

        // Load recipient emails list
        List<string> _lstRecipientEmails = LoadRecipientEmailsList();

        // Check if list are undefined
        if (_lstRecipientEmails == null || !_lstRecipientEmails.Any())
        {
            // Add error message
            _Result.AddError("Undefined recipient!");

            // Return
            return _Result;
        }

        // Generate excel file name
        string _strExcelFileName = Path.Combine(_strExcelFilesPath, string.Concat(Path.GetFileNameWithoutExtension(_strEmailTemplate), "_", Guid.NewGuid().ToString(), ".xlsx"));

        // Create excel file
        bool _blSuccess = ClExcel.CreateExcelFileFromDataTable(_dtRecords, _strExcelFileName);

        // Check success
        if (!_blSuccess)
        {
            // Add error message
            _Result.AddError("Error while creating the Excel file!");

            // Return
            return _Result;
        }

        // Send email
        SendEmail(_lstRecipientEmails, _strEmailTemplate, _strExcelFileName);
    }
    else
    {
        // Add info message
        _Result.AddInfo("No data is available!");

        // Return
        return _Result;
    }

    // Return
    return _Result;
}

/// <summary>
/// Send email
/// </summary>
/// <param name="_lstRecipientEmails">Recipient emails list</param>
/// <param name="_strEmailTemplate">Email template</param>
/// <param name="_strExcelFileName">Excel file name</param>
void SendEmail(List<string> _lstRecipientEmails, string _strEmailTemplate, string _strExcelFileName)
{
    // Email configurations
    string _strFrom = "FromEmail@gmail.com";
    string _strFromPassword = "FromPassword";

    // Create email message
    MailMessage _Message = new MailMessage();

    // Set from address
    _Message.From = new MailAddress(_strFrom);

    // Set subject
    _Message.Subject = "Subject Message!";

    // Set recipient list
    foreach (string item in _lstRecipientEmails)
        _Message.To.Add(new MailAddress(item));

    // Set body message (email template file
    _Message.Body = File.ReadAllText(_strEmailTemplate, Encoding.Default);
    _Message.IsBodyHtml = true;

    // Set attachment (Excel file)
    _Message.Attachments.Add(new Attachment(_strExcelFileName));

    // STMP configurations
    SmtpClient smtpClient = new SmtpClient("smtp.gmail.com")
    {
        Port = 587,
        Credentials = new System.Net.NetworkCredential(_strFrom, _strFromPassword),
        EnableSsl = true
    };

    // Send email
    smtpClient.Send(_Message);
}

/// <summary>
/// Get results from database
/// </summary>
/// <returns>Data table with the query results</returns>
DataTable GetResults()
{
    // Getting data from database should be implemented
}

/// <summary>
/// Load email template
/// </summary>
/// <returns>String with the email template path</returns>
string LoadEmailTemplate()
{
    // Getting the configuration of the email template must be implemented (.html file)
}

/// <summary>
/// Load Excel files path
/// </summary>
/// <returns>String with the Excel files directory</returns>
string LoadExcelFilesPath()
{
    // Getting the configuration of Excel files path must be implemented
}

/// <summary>
/// Load recipient emails list
/// </summary>
/// <returns>List of recipient emails list</returns>
List<string> LoadRecipientEmailsList()
{
    // Getting the recipient emails list must be implemented
}

Embed Power BI in your product for your customers (.NET Framework Embed Report)

Initialize

  1. Install nuget Microsoft.PowerBI.Api.
  2. Install nuget Microsoft.PowerBI.JavaScript.


Models

  • PBISetting.cs
public class PBISetting
{
  public string ApplicationId { get; set; }
  public List<Guid> WorkspaceId { get; set; }
  public List<List<Guid>> ReportId { get; set; }
  public string AuthenticationType { get; set; }
  public string Username { get; set; }
  public string Password { get; set; }
  public string ApplicationSecret { get; set; }
  public string Tenant { get; set; }
}
  • EmbedReport.cs
public class EmbedReport
{
  // Id of Power BI report to be embedded
  public Guid ReportId { get; set; }

  // Name of the report
  public string ReportName { get; set; }

  // Embed URL for the Power BI report
  public string EmbedUrl { get; set; }
}
  • ReportEmbedConfig.cs
public class ReportEmbedConfig
{
  // Report to be embedded
  public List<EmbedReport> EmbedReports { get; set; }

  // Embed Token for the Power BI report
  public EmbedToken EmbedToken { get; set; }
}
  • ErrorModel.cs
public class ErrorModel
{
  public string ErrorMessage { get; internal set; }
}


Services

  • AadService.cs
  public class AadService
  {
    private static readonly string m_authorityUrl = "https://login.microsoftonline.com/organizations";
    private static readonly string[] m_scope = "https://analysis.windows.net/powerbi/api/.default".Split(';');

    /// <summary>
    /// Get Access token
    /// </summary>
    /// <returns>Access token</returns>
    [Obsolete]
    public static async Task<string> GetAccessToken(PBISetting setting)
    {
      AuthenticationResult authenticationResult = null;
      if (setting.AuthenticationType.Equals("masteruser", StringComparison.InvariantCultureIgnoreCase))
      {
        IPublicClientApplication clientApp = PublicClientApplicationBuilder
                                  .Create(setting.ApplicationId)
                                  .WithAuthority(m_authorityUrl)
                                  .Build();
        var userAccounts = await clientApp.GetAccountsAsync();

        try
        {
          authenticationResult = await clientApp.AcquireTokenSilent(m_scope, userAccounts.FirstOrDefault()).ExecuteAsync();
        }
        catch (MsalUiRequiredException)
        {
          SecureString secureStringPassword = new SecureString();
          foreach (var key in setting.Password)
          {
            secureStringPassword.AppendChar(key);
          }
          authenticationResult = await clientApp.AcquireTokenByUsernamePassword(m_scope, setting.Username, secureStringPassword).ExecuteAsync();
        }
      }

      // Service Principal auth is recommended by Microsoft to achieve App Owns Data Power BI embedding
      else if (setting.AuthenticationType.Equals("serviceprincipal", StringComparison.InvariantCultureIgnoreCase))
      {
        // For app only authentication, we need the specific tenant id in the authority url
        var tenantSpecificURL = m_authorityUrl.Replace("organizations", setting.Tenant);

        IConfidentialClientApplication clientApp = ConfidentialClientApplicationBuilder
                                        .Create(setting.ApplicationId)
                                        .WithClientSecret(setting.ApplicationSecret)
                                        .WithAuthority(tenantSpecificURL)
                                        .Build();

        authenticationResult = await clientApp.AcquireTokenForClient(m_scope).ExecuteAsync();
      }

      return authenticationResult.AccessToken;
    }
  }
  • PBIService.cs
  public class PBIService
  {
    public static string CheckSettingError(PBISetting setting)
    {
      string message = null;
      Guid result;

      // Application Id must have a value.
      if (string.IsNullOrWhiteSpace(setting.ApplicationId))
      {
        message = "ApplicationId is empty. please register your application as Native app in https://dev.powerbi.com/apps and fill client Id in setting.";
      }
      // Application Id must be a Guid object.
      else if (!Guid.TryParse(setting.ApplicationId, out result))
      {
        message = "ApplicationId must be a Guid object. please register your application as Native app in https://dev.powerbi.com/apps and fill application Id in setting.";
      }
      // Workspace Id must have a value.
      else if (setting.WorkspaceId.Where(x => x == Guid.Empty).Count() > 0)
      {
        message = "WorkspaceId is empty or not a valid Guid. Please fill its Id correctly in setting";
      }
      // Report Id must have a value.
      else if (setting.ReportId.Where(x => x.Where(y => y == Guid.Empty).Count() > 0).Count() > 0)
      {
        message = "ReportId is empty or not a valid Guid. Please fill its Id correctly in setting";
      }
      else if (setting.AuthenticationType.Equals("masteruser", StringComparison.InvariantCultureIgnoreCase))
      {
        // Username must have a value.
        if (string.IsNullOrWhiteSpace(setting.Username))
        {
          message = "Username is empty. Please fill Power BI username in setting";
        }

        // Password must have a value.
        if (string.IsNullOrWhiteSpace(setting.Password))
        {
          message = "Password is empty. Please fill password of Power BI username in setting";
        }
      }
      else if (setting.AuthenticationType.Equals("serviceprincipal", StringComparison.InvariantCultureIgnoreCase))
      {
        if (string.IsNullOrWhiteSpace(setting.ApplicationSecret))
        {
          message = "ApplicationSecret is empty. please register your application as Web app and fill appSecret in setting.";
        }
        // Must fill tenant Id
        else if (string.IsNullOrWhiteSpace(setting.Tenant))
        {
          message = "Invalid Tenant. Please fill Tenant ID in Tenant under setting";
        }
      }
      else
      {
        message = "Invalid authentication type";
      }

      return message;
    }

    private static Guid GetParamGuid(string param)
    {
      Guid paramGuid = Guid.Empty;
      Guid.TryParse(param, out paramGuid);
      return paramGuid;
    }
  }
  • EmbedService.cs
  public static class EmbedService
  {
    private static readonly string urlPowerBiServiceApiRoot = "https://api.powerbi.com";

    public static async Task<PowerBIClient> GetPowerBiClient(PBISetting setting)
    {
      var tokenCredentials = new TokenCredentials(await AadService.GetAccessToken(setting), "Bearer");
      return new PowerBIClient(new Uri(urlPowerBiServiceApiRoot), tokenCredentials);
    }

    /// <summary>
    /// Get embed params for a report
    /// </summary>
    /// <returns>Wrapper object containing Embed token, Embed URL, Report Id, and Report name for single report</returns>
    public static async Task<ReportEmbedConfig> GetEmbedParams(PBISetting setting, Guid workspaceId, Guid reportId, [Optional] Guid additionalDatasetId)
    {
      using (var pbiClient = await GetPowerBiClient(setting))
      {
        // Get report info
        var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId);

        /*
        Check if dataset is present for the corresponding report
        If no dataset is present then it is a RDL report 
        */
        bool isRDLReport = String.IsNullOrEmpty(pbiReport.DatasetId);

        EmbedToken embedToken;

        if (isRDLReport)
        {
          // Get Embed token for RDL Report
          embedToken = await GetEmbedTokenForRDLReport(setting, workspaceId, reportId);
        }
        else
        {
          // Create list of dataset
          var datasetIds = new List<Guid>();

          // Add dataset associated to the report
          datasetIds.Add(Guid.Parse(pbiReport.DatasetId));

          // Append additional dataset to the list to achieve dynamic binding later
          if (additionalDatasetId != Guid.Empty)
          {
            datasetIds.Add(additionalDatasetId);
          }

          // Get Embed token multiple resources
          embedToken = await GetEmbedToken(setting, reportId, datasetIds, workspaceId);
        }

        // Add report data for embedding
        var embedReports = new List<EmbedReport>() {
          new EmbedReport
          {
            ReportId = pbiReport.Id, ReportName = pbiReport.Name, EmbedUrl = pbiReport.EmbedUrl
          }
        };

        // Capture embed params
        var embedParams = new ReportEmbedConfig
        {
          EmbedReports = embedReports,
          EmbedToken = embedToken
        };

        return embedParams;
      }
    }

    /// <summary>
    /// Get embed params for multiple reports for a single workspace
    /// </summary>
    /// <returns>Wrapper object containing Embed token, Embed URL, Report Id, and Report name for multiple reports</returns>
    /// <remarks>This function is not supported for RDL Report</remakrs>
    public static async Task<ReportEmbedConfig> GetEmbedParams(PBISetting setting, Guid workspaceId, IList<Guid> reportIds, [Optional] IList<Guid> additionalDatasetIds)
    {
      // Note: This method is an example and is not consumed in this sample app

      using (var pbiClient = await GetPowerBiClient(setting))
      {
        // Create mapping for reports and Embed URLs
        var embedReports = new List<EmbedReport>();

        // Create list of datasets
        var datasetIds = new List<Guid>();

        // Get datasets and Embed URLs for all the reports
        foreach (var reportId in reportIds)
        {
          // Get report info
          var pbiReport = pbiClient.Reports.GetReportInGroup(workspaceId, reportId);

          // Append to existing list of datasets to achieve dynamic binding later
          datasetIds.Add(Guid.Parse(pbiReport.DatasetId));

          // Add report data for embedding
          embedReports.Add(new EmbedReport { ReportId = pbiReport.Id, ReportName = pbiReport.Name, EmbedUrl = pbiReport.EmbedUrl });
        }

        // Append to existing list of datasets to achieve dynamic binding later
        if (additionalDatasetIds != null)
        {
          datasetIds.AddRange(additionalDatasetIds);
        }

        // Get Embed token multiple resources
        var embedToken = await GetEmbedToken(setting, reportIds, datasetIds, workspaceId);

        // Capture embed params
        var embedParams = new ReportEmbedConfig
        {
          EmbedReports = embedReports,
          EmbedToken = embedToken
        };

        return embedParams;
      }
    }

    /// <summary>
    /// Get Embed token for single report, multiple datasets, and an optional target workspace
    /// </summary>
    /// <returns>Embed token</returns>
    /// <remarks>This function is not supported for RDL Report</remakrs>
    public static async Task<EmbedToken> GetEmbedToken(PBISetting setting, Guid reportId, IList<Guid> datasetIds, [Optional] Guid targetWorkspaceId)
    {
      using (var pbiClient = await GetPowerBiClient(setting))
      {
        // Create a request for getting Embed token 
        // This method works only with new Power BI V2 workspace experience
        var tokenRequest = new GenerateTokenRequestV2(

        reports: new List<GenerateTokenRequestV2Report>() { new GenerateTokenRequestV2Report(reportId) },

        datasets: datasetIds.Select(datasetId => new GenerateTokenRequestV2Dataset(datasetId.ToString())).ToList(),

        targetWorkspaces: targetWorkspaceId != Guid.Empty ? new List<GenerateTokenRequestV2TargetWorkspace>() { new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId) } : null
        );

        // Generate Embed token
        var embedToken = pbiClient.EmbedToken.GenerateToken(tokenRequest);

        return embedToken;
      }
    }

    /// <summary>
    /// Get Embed token for multiple reports, datasets, and an optional target workspace
    /// </summary>
    /// <returns>Embed token</returns>
    /// <remarks>This function is not supported for RDL Report</remakrs>
    public static async Task<EmbedToken> GetEmbedToken(PBISetting setting, IList<Guid> reportIds, IList<Guid> datasetIds, [Optional] Guid targetWorkspaceId)
    {
      // Note: This method is an example and is not consumed in this sample app

      using (var pbiClient = await GetPowerBiClient(setting))
      {
        // Convert reports to required types
        var reports = reportIds.Select(reportId => new GenerateTokenRequestV2Report(reportId)).ToList();

        // Convert datasets to required types
        var datasets = datasetIds.Select(datasetId => new GenerateTokenRequestV2Dataset(datasetId.ToString())).ToList();

        // Create a request for getting Embed token 
        // This method works only with new Power BI V2 workspace experience
        var tokenRequest = new GenerateTokenRequestV2(

          datasets: datasets,

          reports: reports,

          targetWorkspaces: targetWorkspaceId != Guid.Empty ? new List<GenerateTokenRequestV2TargetWorkspace>() { new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId) } : null
        );

        // Generate Embed token
        var embedToken = pbiClient.EmbedToken.GenerateToken(tokenRequest);

        return embedToken;
      }
    }

    /// <summary>
    /// Get Embed token for multiple reports, datasets, and optional target workspaces
    /// </summary>
    /// <returns>Embed token</returns>
    /// <remarks>This function is not supported for RDL Report</remakrs>
    public static async Task<EmbedToken> GetEmbedToken(PBISetting setting, IList<Guid> reportIds, IList<Guid> datasetIds, [Optional] IList<Guid> targetWorkspaceIds)
    {
      // Note: This method is an example and is not consumed in this sample app

      using (var pbiClient = await GetPowerBiClient(setting))
      {
        // Convert report Ids to required types
        var reports = reportIds.Select(reportId => new GenerateTokenRequestV2Report(reportId)).ToList();

        // Convert dataset Ids to required types
        var datasets = datasetIds.Select(datasetId => new GenerateTokenRequestV2Dataset(datasetId.ToString())).ToList();

        // Convert target workspace Ids to required types
        IList<GenerateTokenRequestV2TargetWorkspace> targetWorkspaces = null;
        if (targetWorkspaceIds != null)
        {
          targetWorkspaces = targetWorkspaceIds.Select(targetWorkspaceId => new GenerateTokenRequestV2TargetWorkspace(targetWorkspaceId)).ToList();
        }

        // Create a request for getting Embed token 
        // This method works only with new Power BI V2 workspace experience
        var tokenRequest = new GenerateTokenRequestV2(

          datasets: datasets,

          reports: reports,

          targetWorkspaces: targetWorkspaceIds != null ? targetWorkspaces : null
        );

        // Generate Embed token
        var embedToken = pbiClient.EmbedToken.GenerateToken(tokenRequest);

        return embedToken;
      }
    }

    /// <summary>
    /// Get Embed token for RDL Report
    /// </summary>
    /// <returns>Embed token</returns>
    public static async Task<EmbedToken> GetEmbedTokenForRDLReport(PBISetting setting, Guid targetWorkspaceId, Guid reportId, string accessLevel = "view")
    {
      using (var pbiClient = await GetPowerBiClient(setting))
      {

        // Generate token request for RDL Report
        var generateTokenRequestParameters = new GenerateTokenRequest(
          accessLevel: accessLevel
        );

        // Generate Embed token
        var embedToken = pbiClient.Reports.GenerateTokenInGroup(targetWorkspaceId, reportId, generateTokenRequestParameters);

        return embedToken;
      }
    }
  }


Controllers

public class HomeController : Controller
{
  private string m_errorMessage;
  
  [Obsolete]
  public async Task<ActionResult> Index()
  {
    //Get User
    UserModel user = new UserModel();
    var users = crm.User.Where(x => x.IsActive == true).ToList();
    user = users.Where(x => x.ID.Equals(SessionHelper.UserID)).FirstOrDefault();
  
    if (user == null)
    {
      return RedirectToAction("Login", "Account");
    }
  
    //Get ClientProfile
    ClientProfileModel client = new ClientProfileModel();
    client = crm.ClientProfile.Where(x => x.ID.Equals(SessionHelper.ClientProfileID)).FirstOrDefault();
  
    if (client == null)
    {
      return RedirectToAction("Login", "Account");
    }
  
    //Get Workspaces
    List<PowerBIWorkspaceModel> workspace = new List<PowerBIWorkspaceModel>();
    var workspaces = crm.PowerBIWorkspace.Where(x => x.IsActive == true).ToList();
  
    if (user.PowerBIWorkspaceID != null)
    {
      workspace = workspaces.Where(x => user.PowerBIWorkspaceID.Split(',').ToList().Contains(x.ID.ToString())).ToList();
    }
  
    //Get Embeded
    List<PowerBIEmbedModel> embeds = new List<PowerBIEmbedModel>();
    List<List<Guid>> EmbedId = new List<List<Guid>>();
    List<List<string>> EmbedType = new List<List<string>>();
    List<List<string>> EmbedTitle = new List<List<string>>();
    embeds = crm.PowerBIEmbed.Where(x => x.IsActive == true).ToList();
    foreach (var w in workspace)
    {
      var e = embeds.Where(x => x.WorkspaceID.ToString() == w.ID.ToString());
      EmbedId.Add(e.Select(x => new Guid(x.EmbedID)).ToList());
    }
  
    string ApplicationId = client.PowerBIApplicationID;
    List<Guid> WorkspaceId = workspace.Select(x => new Guid(x.WorkspaceID)).ToList();
    string AuthenticationType = "masteruser";
    string ApplicationSecret = "";
    string Tenant = "";
    string Username = workspace.Select(x => x.PBIUsername).ToList().FirstOrDefault();
    string Password = workspace.Select(x => x.PBIPassword).ToList().FirstOrDefault();
  
    PBISetting setting = new PBISetting();
    setting.ApplicationId = ApplicationId;
    setting.WorkspaceId = WorkspaceId;
    setting.EmbedId = EmbedId;
    setting.EmbedType = EmbedType;
    setting.EmbedTitle = EmbedTitle;
    setting.AuthenticationType = AuthenticationType;
    setting.Username = Username;
    setting.Password = Password;
    setting.ApplicationSecret = ApplicationSecret;
    setting.Tenant = Tenant;
  
    m_errorMessage = PBIService.CheckSettingError(setting);
  
    if (!m_errorMessage.IsNullOrWhiteSpace())
    {
      return View("Error", BuildErrorModel(m_errorMessage));
    }
  
    try
    {
      EmbedConfig results = new EmbedConfig();
      List<ReportEmbedConfig> reportList = new List<ReportEmbedConfig>();
      List<DashboardEmbedConfig> dashboardList = new List<DashboardEmbedConfig>();
      List<TileEmbedConfig> tileList = new List<TileEmbedConfig>();
  
      for (int w = 0; w < setting.WorkspaceId.Count; w++)
      {
        var embedReport = await EmbedService.GetEmbedParams(setting, setting.WorkspaceId[w], setting.EmbedId[w]);
        reportList.Add(embedReport);
      }
  
      results.Reports = reportList;
      results.Dashboards = dashboardList;
      results.Tiles = tileList;
  
      return View(results);
    }
    catch (Exception ex)
    {
      //m_errorMessage = "Operation failed: system error. please contact your system administrator.";
      m_errorMessage = ex.Message;
      return View("Error", BuildErrorModel(m_errorMessage));
    }
  }
  
  private ErrorModel BuildErrorModel(string errorMessage)
  {
    return new ErrorModel
    {
      ErrorMessage = errorMessage
    };
  }
}


View

@if (Model.Count > 0)
{
    for (int i = 0; i < Model.Count; i++)
    {
        for (int j = 0; j < Model[i].EmbedReports.Count; j++)
        {
            string id = "embedContainer_" + i + "_" + j;


            <div id="@id" class="mb-3" style="height:@height"></div>
        }
    }
}

<script src="~/Scripts/powerbi-client/dist/powerbi.min.js"></script>
@if (Model.Count > 0)
{
    <script>
        // Get a reference to the embedded report HTML element
        const reportContainer = [];


        @for (int i = 0; i < Model.Count; i++)
        {
            for (int j = 0; j < Model[i].EmbedReports.Count; j++)
            {
                @:reportContainer.push($(`#embedContainer_@(i)_@(j)`)[0]);
            }
        }


        // Read embed application token from Model
        const accessToken = [];


        @for (int i = 0; i < Model.Count; i++)
        {
            for (int j = 0; j < Model[i].EmbedReports.Count; j++)
            {
                @:accessToken.push(`@(Model[i].EmbedToken.Token)`);
            }
        }


        // You can embed different reports as per your need by changing the index
        // Read embed URL from Model
        const embedUrl = [];


        @for (int i = 0; i < Model.Count; i++)
        {
            for (int j = 0; j < Model[i].EmbedReports.Count; j++)
            {
                @:embedUrl.push(`@(Model[i].EmbedReports[j].EmbedUrl)`);
            }
        }


        // Read report Id from Model
        const embedReportId = [];


        @for (int i = 0; i < Model.Count; i++)
        {
            for (int j = 0; j < Model[i].EmbedReports.Count; j++)
            {
                @:embedReportId.push(`@`(Model[i].EmbedReports[j].ReportId)`);
            }
        }


        // Use the token expiry to regenerate Embed token for seamless end user experience
        // Refer https://aka.ms/RefreshEmbedToken
        const tokenExpiry = [];


        @for (int i = 0; i < Model.Count; i++)
        {
            for (int j = 0; j < Model[i].EmbedReports.Count; j++)
            {
                @:embedReportId.push(`@(Html.Raw(Model[i].EmbedToken.Expiration))`);
            }
        }


        // Get models. models contains enums that can be used.
        const models = window['powerbi-client'].models;

        // Embed configuration used to describe the what and how to embed.
        // This object is used when calling powerbi.embed.
        // This also includes settings and options such as filters.
        // You can find more information at https://github.com/Microsoft/PowerBI-JavaScript/wiki/Embed-Configuration-Details.
        for (let i = 0; i < reportContainer.length; i++) {
            const config = {
                type: 'report',
                tokenType: models.TokenType.Embed,
                accessToken: accessToken[i],
                embedUrl: embedUrl[i],
                id: embedReportId[i],
                permissions: models.Permissions.All,
                settings: {
                    // Enable this setting to remove gray shoulders from embedded report
                    // background: models.BackgroundType.Transparent,
                    filterPaneEnabled: true,
                    navContentPaneEnabled: true
                }
            };


            // Embed the report and display it within the div container.
            const report = powerbi.embed(reportContainer[i], config);
        }
    </script>
}



Empty IQueryable Class

Enumerable.Empty<ClassName>().AsQueryable();

Enable Cross-Origin Requests (CORS) in ASP.NET Core

Store Allowed Domains in appsettings.json: Instead of hardcoding the allowed domains in the code, we can define them in the configuration file:

{
  "AllowedOrigins": [
    "https://app1.example.com",
    "https://app2.example.com",
    "https://mobile.example.com"
  ]
}


Retrieved the array of allowed origins from the app settings and used them to register CORS services :

string allowedSpecificOrigins = "AllowSpecificOrigins";
WebApplicationBuilder? builder = WebApplication.CreateBuilder(args);
string[]? allowedOrigins = builder
                 .Configuration
                 .GetSection("AllowedOrigins")
                 .Get<string[]>();
builder.Services.AddCors(options =>
{
    options.AddPolicy(allowedSpecificOrigins,
        policy =>
           {
               policy.WithOrigins(allowedOrigins)
                     .AllowAnyMethod()
                     .AllowAnyHeader();
            });
});
builder.Services.AddControllers();


Enable CORS middleware

app.UseCors(allowedSpecificOrigins);

Enable debugging access for my website

Set debug to true in Web.config file.


<compilation debug="true" strict="false" explicit="true">

</compilation>

Enable Global Split Queries in .Net Core

This configuration ensures that all LINQ queries using Include() in Entity Framework Core are executed using split queries by default. This helps prevent performance issues caused by Cartesian explosion when loading multiple related collections. It is enabled by setting UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery) in the DbContext configuration.


builder.Services.AddDbContext<YourDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"))
           .UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)
);


Alternative configuration in DbContext

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(connectionString)
        .UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
}


Or in OnModelCreating for specific configurations

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // Configure split query behavior
    modelBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
    
    base.OnModelCreating(modelBuilder);
}

Enable Sensitive Data Logging in .Net Core

if (env.IsDevelopment())
{
    options.EnableSensitiveDataLogging();
    options.EnableDetailedErrors();
}

Enable Server GC in .NET Core

To enable Server GC, modify the runtimeconfig.json file or add the following to your app settings:

{
  "runtimeOptions": {
    "configProperties": {
      "System.GC.Server": true
    }
  }
}


Alternatively, you can configure GC in ASP.NET Core apps by editing Program.cs:

public static void Main(string[] args)
{
    var host = Host.CreateDefaultBuilder(args)
        .UseServerGC()  // Enables Server GC mode
        .Build();

    host.Run();
}

Enhancing File Upload Security in .NET Core with File Signature Validation

Why Use File Signature Validation? —


  • Prevents Spoofing Attacks — Attackers may rename a file (e.g., .exe to .jpg) to bypass extension-based filtering.
  • Stops Malware Uploads — Ensures that only legitimate file types are processed and prevents execution of malicious scripts.
  • Improves Data Integrity — Helps detect tampered files before they are stored or executed.
  • Enhances Compliance — Many regulatory standards (e.g., PCI DSS, HIPAA) require secure file handling.


How File Signature Validation Works —


Extract File Signature —

  • Every file format has a unique binary signature (also called "magic number") at the beginning of the file.
  • This signature is compared against a list of allowed file types.


Validate Against Expected Format: —

  • Check if the extracted signature matches the expected format.
  • If the signature doesn't match the extension, reject the upload.


Perform Additional Security Checks

  • Virus Scanning: Use an antivirus engine to scan files.
  • Size Restrictions: Set limits to prevent DoS attacks via large file uploads.
  • Content-Type Verification: Ensure that the MIME type matches the file's actual content.


Steps to Implement File Signature Validation in .NET Core


Define Allowed File Signatures: -

Each file type has a unique signature (byte sequence) at the beginning of the file. Below are some common file signatures:

None


Define a dictionary to map file types to their signatures:

public static class FileSignatures
{
    public static readonly Dictionary<string, List<byte[]>> Signatures = new()
    {
        { ".jpg", new List<byte[]> { new byte[] { 0xFF, 0xD8, 0xFF } } },
        { ".png", new List<byte[]> { new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A } } },
        { ".pdf", new List<byte[]> { new byte[] { 0x25, 0x50, 0x44, 0x46 } } },
        { ".docx", new List<byte[]> { new byte[] { 0x50, 0x4B, 0x03, 0x04 } } } // DOCX is a ZIP file format
    };
}


Validate File Signature During Upload: —

Use the file stream to read the first few bytes and compare them against the allowed signatures.

public static bool IsValidFileSignature(Stream fileStream, string fileExtension)
{
    if (!FileSignatures.Signatures.ContainsKey(fileExtension))
        return false; // File type is not allowed

    var allowedSignatures = FileSignatures.Signatures[fileExtension];

    using (var reader = new BinaryReader(fileStream))
    {
        foreach (var signature in allowedSignatures)
        {
            fileStream.Position = 0; // Reset stream position before reading
            var headerBytes = reader.ReadBytes(signature.Length);

            if (headerBytes.SequenceEqual(signature))
                return true; // Valid file signature
        }
    }

    return false; // Invalid file signature
}


Implement File Validation in Controller : —

Modify the file upload controller to validate the file signature before saving.

[HttpPost("upload")]
public async Task<IActionResult> UploadFile(IFormFile file)
{
    if (file == null || file.Length == 0)
        return BadRequest("File is empty.");

    var extension = Path.GetExtension(file.FileName).ToLowerInvariant();
    
    using var fileStream = file.OpenReadStream();
    if (!IsValidFileSignature(fileStream, extension))
        return BadRequest("Invalid file format.");

    var filePath = Path.Combine("Uploads", file.FileName);
    using (var stream = new FileStream(filePath, FileMode.Create))
    {
        await file.CopyToAsync(stream);
    }

    return Ok("File uploaded successfully.");
}

Enum to List

enumClass[] enumList = (enumClass[])Enum.GetValues(typeof(enumClass));

Evaluate Expressions in Switch Statements

switch (mark)
{
    case int n when n >= 80:
        Console.WriteLine("Grade is A");
        break;
    case int n when n >= 60:
        Console.WriteLine("Grade is B");
        break;
    case int n when n >= 40:
        Console.WriteLine("Grade is C");
        break;
    default:
        Console.WriteLine("Grade is D");
        break;
}

Exception Logging In MVC Using Elmah

Install Elmah Package from Nuget.


Now open web config file and add the following code inside <system.web> </system.web>.

<!--add this-->  
    < httpHandlers >  
    < add verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >  
    < /httpHandlers>  
<!--add this-->  


Also, add the following code inside <system.webServer></system.webServer>.

<!--add this-->  
    < handlers >  
    < add name = "Elmah"verb = "POST,GET,HEAD"path = "elmah.axd"type = "Elmah.ErrorLogPageFactory, Elmah" / >  
    < /handlers>  
<!--add this-->  


Create ELMAH_Error table.

CREATE TABLE[dbo].[ELMAH_Error]  
(  
  
    [ErrorId][uniqueidentifier] NOT NULL,  
  
    [Application][nvarchar](60) NOT NULL,  
  
    [Host][nvarchar](50) NOT NULL,  
  
    [Type][nvarchar](100) NOT NULL,  
  
    [Source][nvarchar](60) NOT NULL,  
  
    [Message][nvarchar](500) NOT NULL,  
  
    [User][nvarchar](50) NOT NULL,  
  
    [StatusCode][int] NOT NULL,  
  
    [TimeUtc][datetime] NOT NULL,  
  
    [Sequence][int] IDENTITY(1, 1) NOT NULL,  
  
    [AllXml][ntext] NOT NULL  
)  


Create stored procedures.

ELMAH_GetErrorsXml

Create PROCEDURE[dbo].[ELMAH_GetErrorsXml]  
  
(  
    @Application NVARCHAR(60),  
    @PageIndex INT = 0,  
    @PageSize INT = 15,  
    @TotalCount INT OUTPUT  
  
)  
  
AS  
  
SET NOCOUNT ON  
  
DECLARE @FirstTimeUTC DATETIME  
DECLARE @FirstSequence INT  
DECLARE @StartRow INT  
DECLARE @StartRowIndex INT  
SELECT  
  
@TotalCount = COUNT(1)  
  
FROM  
  
    [ELMAH_Error]  
  
WHERE  
  
    [Application] = @Application  
SET @StartRowIndex = @PageIndex * @PageSize + 1  
IF @StartRowIndex <= @TotalCount  
  
BEGIN  
  
SET ROWCOUNT @StartRowIndex  
  
SELECT  
  
@FirstTimeUTC = [TimeUtc],  
  
    @FirstSequence = [Sequence]  
  
FROM  
  
    [ELMAH_Error]  
  
WHERE  
  
    [Application] = @Application  
  
ORDER BY  
  
    [TimeUtc] DESC,  
    [Sequence] DESC  
  
END  
  
ELSE  
  
BEGIN  
  
SET @PageSize = 0  
  
END  
  
SET ROWCOUNT @PageSize  
  
SELECT  
  
errorId = [ErrorId],  
  
    application = [Application],  
    host = [Host],  
    type = [Type],  
    source = [Source],  
    message = [Message],  
    [user] = [User],  
    statusCode = [StatusCode],  
    time = CONVERT(VARCHAR(50), [TimeUtc], 126) + 'Z'  
  
FROM  
  
    [ELMAH_Error] error  
  
WHERE  
  
    [Application] = @Application  
  
AND  
  
    [TimeUtc] <= @FirstTimeUTC  
  
AND  
  
    [Sequence] <= @FirstSequence  
  
ORDER BY  
  
    [TimeUtc] DESC,  
  
    [Sequence] DESC  
  
FOR  
  
XML AUTO  


ELMAH_GetErrorXml

Create PROCEDURE[dbo].[ELMAH_GetErrorXml]  
  
(  
  
    @Application NVARCHAR(60),  
    @ErrorId UNIQUEIDENTIFIER  
  
)  
  
AS  
  
SET NOCOUNT ON  
SELECT  
  
    [AllXml]  
FROM  
  
    [ELMAH_Error]  
WHERE  
  
    [ErrorId] = @ErrorId  
AND  
    [Application] = @Application  


ELMAH_LogError

Create PROCEDURE[dbo].[ELMAH_LogError]  
  
(  
  
    @ErrorId UNIQUEIDENTIFIER,    
    @Application NVARCHAR(60),    
    @Host NVARCHAR(30),    
    @Type NVARCHAR(100),  
    @Source NVARCHAR(60),    
    @Message NVARCHAR(500),  
    @User NVARCHAR(50),   
    @AllXml NTEXT,    
    @StatusCode INT,   
    @TimeUtc DATETIME  
  
)  
  
AS  
  
SET NOCOUNT ON  
  
INSERT  
  
INTO  
  
    [ELMAH_Error]
(  
  
    [ErrorId],   
    [Application],   
    [Host],  
    [Type],  
    [Source],  
    [Message],    
    [User],    
    [AllXml],    
    [StatusCode],    
    [TimeUtc]  
  
)  
  
VALUES  
  
    (  
  
    @ErrorId,  
    @Application,    
    @Host,    
    @Type,    
    @Source,   
    @Message,    
    @User,   
    @AllXml,   
    @StatusCode,   
    @TimeUtc  
  
)  


Now again open web config file, add the following code inside in <configuration>.

</configuration>  
<elmah>  
    <!--. If allowRemoteAccess value is set to 0, then the error log web page can only be viewed locally. If allowRemoteAccess attribute is set to 1 then the error log web page is enabled for both remote and local visitors.-->  
    <!--add this-->  
    <security allowRemoteAccess="0" />  
    <!--  DefaultConnection is the name of database connection string -->  
    <errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="DefaultConnection" />  
    <!--add this-->  
</elmah>   


Note: You can view the error log web page through the url localhost:portno/elmah.axd like, localhost:55776/elmah.axd.