Fransiscus Setiawan | EV Charging & Azure Solution Architect | Sydney

Technical Insights: Azure, .NET, Dynamics 365 & EV Charging Architecture

Generic Logging Class in .NET

This is a snippet code which is useful in creating your own logging class. You can compile this as a library and use it accross the projects.

using System;
using System.Configuration;
using System.Diagnostics;
using System.Reflection;

namespace MyLogging
{
    /// 
    /// provides event logging capabilities
    ///
    /// requires a LogSource setting in app/web.config, which must match the name of the event log
    /// 
    public class Logger
    {
        #region constants

        static readonly string ERROR_NOSOURCE = "MyLogging - cannot write to event log - please specify a LogSource in app/web.config";

        #endregion

        #region static ctor

        static Logger()
        {
            if (ConfigurationManager.AppSettings["LogSource"] == null)
            {
                throw new ApplicationException(ERROR_NOSOURCE);
            }
            else
            {
                _source = ConfigurationManager.AppSettings["LogSource"].ToString();

                if (!EventLog.SourceExists(_source))
                {
                    EventLog.CreateEventSource(_source, "Application");
                    EventLog.WriteEntry(_source, "log source created");
                }
            }
        }

        #endregion

        #region properties - LogSource

        private static string _source = null;

        public static string LogSource
        {
            get { return _source; }
            set { _source = value; }
        }

        #endregion

        #region public logging methods

        /// 
        /// logs an exception, using reflection to determine calling method and module
        /// 
        /// 
        public static void LogException(Exception ex)
        {
            MethodBase  method = ex.TargetSite;
            Module      module = method.Module;

            string      msg = module.Name + "." + method.Name
                            + " - " + ex.Message
                            + Environment.NewLine
                            + "Stack Trace - " + ex.StackTrace;

            LogMessage(msg, EventLogEntryType.Error);
        }

        /// 
        /// logs a (non-error) message
        /// 
        /// 
        public static void LogMessage(string message)
        {
            LogMessage(message, EventLogEntryType.Information);
        }

        /// 
        /// logs a message, with specified EventLogEntryType
        /// 
        /// 
        /// 
        private static void LogMessage(string message, EventLogEntryType type)
        {
            message = Assembly.GetExecutingAssembly().FullName + " - " + message;

            //if (_source == null)
            //{
            //    throw new ApplicationException(ERROR_NOSOURCE);
            //}

            EventLog.WriteEntry(_source, message, type);
        }

        #endregion
    }
}

overriding maximum file upload size in ASP.NET

To override maximum file size that can be uploaded in you website, you need to put this in your web.config

      
        
      

Another Entry to My Blog

I’ve decided to buy a domain which basically link to the same server. My new domain is http://www.fransiscus.com.au and at the same time I’ll migrate my content from Joomla to WordPress .I will try to blog more and writing a better blog to share more .NET knowledge with everyone. I feel so excited to move to my new workplace on the 8th september 2008 🙂 and I hope new place = new project = new knowledge to be shared with everyone

CSV parsing in SQL server

I’ve got this SQL Function to parse comma separated value into a table. We need this function when our application commit separated comma value in a text. We normally do this when we want to send an array of value to the SQL server

CREATE FUNCTION [dbo].[SplitCSV](@CSV text)
-- Returns a table with txtValue column
RETURNS @OutTable table(txtValue text)
AS
BEGIN

declare @currentposition int
declare @nextposition    int
declare @lengthOfString  int

-- Assign the starting position of the string
SET @currentposition = 0
 -- The reason for this is to force entrance into the while loop below.
SET @nextposition = 1

WHILE @nextposition > 0
BEGIN
-- Assign the next position to be the current index of ',' + 1
SELECT @nextposition = charindex(',', @CSV, @currentposition + 1)

-- In here we need to find 2 things. The position of the ','
-- and the length of the string segment in between.
SELECT @lengthOfString = CASE WHEN @nextposition > 0
       THEN @nextposition
       ELSE DATALENGTH(@CSV) + 1
       END - @currentposition - 1

--After the length and position is found all we need to do
--is take the substring of the string passed in.
INSERT @OutTable (txtValue)
       VALUES (substring(@CSV, @currentposition + 1, @lengthOfString))

--Set the current position to the next position
SELECT @currentposition = @nextposition
END
RETURN
END

Usage in SQL Query

SELECT
	VenueID
FROM
	Venues
WHERE
	PostCode
IN
	(SELECT CAST(txtValue as VarChar) FROM dbo.splitcsv(@PostCode))

Project item ‘4294967294’ does not represent a file

Project item ‘4294967294’ does not represent a file, this error comes out when I try to open a solution which results in some of the projects can not be loaded (the source file is on the right location and path). I’ve spent two hours to three hours to resolve this issue.
This problem can be resolved by checking out all the files under that solution (from tfs explorer, before you open the solution on your visual studio) and it will resolve the problem for sure. but it’s not practical if you keep doing this and it’s not good to check out all the files if you are not using it.

The root of this problem is caused by Reporting Project. in detail,I’ve checked in reportname.rdl.data for every single report and reportsprojectname.rptproj.user file. Those files must not be checked in at all, remove it from your TFS or VSS and it will work.

Dynamic Order By in ROW_NUMBER()

How to do order by in your paging using ROW_NUMBER() feature on SQL Server 2005

SELECT a.CurrentPrice, a.LotQuantity, a.IsAuction,
	a.AuctionID, a.AuctionName, a.DateStart, a.DateFinish,
	a.StartingPrice, a.ReservePrice, a.FixedPrice, a.BidIncrement,
	p.ProductID, p.CategoryID, p.BrandID, p.ProductName, p.ContentID, p.ThumbImageID,
	Row_Number() OVER
	(
		ORDER BY
		CASE
			WHEN @OrderBy = 'Price_ASC'	THEN CurrentPrice
			WHEN @OrderBy = 'ClosingSoon_ASC'	THEN ISNULL(DateFinish, DATEADD(DAY, 100, GETDATE()))
		END ASC,
		CASE
			WHEN @OrderBy = 'Price_DESC'		THEN CurrentPrice
			WHEN @OrderBy = 'ClosingSoon_DESC'	THEN ISNULL(DateFinish, DATEADD(DAY, 100, GETDATE()))
		END DESC,
		CASE
		       WHEN @OrderBy = 'Name_ASC'			THEN AuctionName
		END ASC,
		CASE
		       WHEN @OrderBy = 'Name_DESC'			THEN AuctionName
		END DESC
		) AS RowNum
FROM Auction a
	INNER JOIN Products p ON a.ProductID = p.ProductID
	INNER JOIN [Content] c ON p.ContentID = c.ContentID

webform_dopostbackwithoptions is undefined

A few days back I’ve got the error message “webform_dopostbackwithoptions is undefined” on the project that i’m working on.
The strange thing it happened only when I activated the securepagemodule, when i deactivated the module it works perfectly. I tried to debug it with HTTP debugger (fiddler tool) and i found that on that particular page, there is a request from webresources.axd but the request is not into https but into http and what i believe since the page is on secure mode therefore it discards the “webresources.axd” since it’s not secure. The workaround for this issue is by adding entry of “webresources.axd” under securepage and the problem is solved.

This is the sample of web.config for it

 
        
         
   </secureWebPages

NOTE:This is resolved in the new version of securepage module

Using Transaction Scope on .NET

Basic Requirements:

1. Have the MSDTC(Distributed Transaction Coordinator) windows service running on your machine
2. Be talking to a SQL 2000 or 2005 Database configured likewise
3. Run this registry script to fix the windows XP SP2 that was causing MSDTC to fail (save as “.reg”)

Registry Script

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\RPC]
"RestrictRemoteClients"=dword:00000000

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Rpc\Internet]
"Ports"=hex(7):31,00,30,00,32,00,35,00,2d,00,31,00,30,00,35,00,35,00,00,00,00,\
  00
"PortsInternetAvailable"="Y"
"UseInternetPorts"="Y"

You can create a class/library to wrap the transaction code
Code:

using System;
using System.Data;
using System.Transactions;

namespace BusinessLayer
{
    public class TransactionScopeWrapper : IDisposable
    {
        private TransactionScope _scope = null;

        public TransactionScopeWrapper()
        {
            if (ConfigHelper.UseTransactionScope)
            {
                int timeout = ConfigHelper.TransactionTimeoutMinutes;

                if (timeout == int.MinValue)
                {
                    timeout = 10;
                }

                _scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, timeout, 0));
            }
        }

        public void Complete()
        {
            if (_scope != null)
            {
                _scope.Complete();
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            if (_scope != null)
            {
                _scope.Dispose();
            }
        }

        #endregion
    }
}

Usage of the wrapper:

public void CancelAuction(int auctionid)
        {
            using (TransactionScopeWrapper scope = new TransactionScopeWrapper())
            {
                tdsAuction.AuctionDataTable auctionTable = AuctionAdapter.AuctionSelect(auctionid);

                if (auctionTable.Rows.Count > 0)
                {
                    tdsAuction.AuctionRow auctionRow = auctionTable.Rows[0] as tdsAuction.AuctionRow;

                    auctionRow.AuctionStatusID = (int)AuctionStatusEnum.Cancelled;
                    AuctionAdapter.Update(auctionRow);

                    // return the Stock to inventory
                    if (auctionRow.IsAuction)
                    {
                        InventoryData.InventoryReturnLotsCancelAuction(auctionid);
                    }
                    else
                    {
                        InventoryData.InventoryReturnLotsForDeal(auctionid);
                    }
                }

                scope.Complete();
            }
        }

the server committed a protocol violation section= responsestatusline

I’ve got this error and try to spend almost an hour to resolve this:

“the server committed a protocol violation section= responsestatusline” when I tried to get the response back from the payment gateway. It happens when you send HTTP Request one after another on the same page. The solution is to add unsafeheaderparsing to true in web.config and to seet keepAlive property to false from the http request it self

Web.Config


		
			
		
		
			
		
    
      
        
      
    
  

Calling Code:

   Private Function SendXML(ByVal strSend As String) As Boolean
        Dim blnSuccess As Boolean = False
        Dim objSendXML As XmlDocument
        Dim objRequest As HttpWebRequest
        Dim mywriter As StreamWriter
        Dim objResponse As HttpWebResponse
        Dim objReturnedXML As XmlDataDocument
        Dim objElementRoot As XmlElement
        Dim objElementTransaction As XmlNode
        Dim objElementCreditCardInfo As XmlNode
        Dim x As XmlNode

        Dim strApproved As String = String.Empty
        Dim blnCreditCardInfo As Boolean = False

        ' Must reset the variable incase of error
        Me._Paid = False

        objSendXML = New XmlDocument
        objRequest = WebRequest.Create(strPaymentURL)


        'if it is using proxy/behind proxy
        If (UseProxy And Not (String.IsNullOrEmpty(ProxyServer))) Then
            objRequest.Proxy = New System.Net.WebProxy(ProxyServer, True)

            'if there is credential
            If (UseDefaultCredential) Then
                objRequest.Proxy.Credentials = CredentialCache.DefaultCredentials
            Else
                objRequest.Proxy.Credentials = New NetworkCredential(UserName, Password)
            End If

        End If

        objRequest.Method = "POST"
        objRequest.ContentLength = strSend.Length
        objRequest.ContentType = "text/xml"

        'to solve protocol violation problem
        objRequest.KeepAlive = False

Paging through strored procedure in sql server

This is very important for the most web developers. This stored procedure accept parameter of page index and page size. By using this paging, you don’t need to store everything in your viewstate which in the end will cause performance suffer. This will load up the necessary result based on the page index and page size and it uses row number to put the number in each row.

Datagrid needs to use custom paging = true as well as virtualitem count to produce the number for paging.

Datagrid in ASPX Page


            
                
                
                
                    
                    
                    
                    
                    
                    
                
                
                
            

Code Behind

//function to do the paging itself
  private void LoadContent(int pageIndex)
    {
        _presenter.GetContentSubmissionSelect(pendingStatusID, pageIndex, PAGE_SIZE);

        if (GetContentSubmissionSelect.Rows.Count > 0)
        {
            lblNoContent.Visible = false;

            dgTaskList.Visible = true;
            dgTaskList.AllowCustomPaging = true;
            dgTaskList.AllowPaging = true;
            dgTaskList.PageSize = PAGE_SIZE;
            _presenter.GetContentSubmissionCount(pendingStatusID);

            dgTaskList.VirtualItemCount = Convert.ToInt32(GetContentSubmissionCount.Rows[0][0]);
            dgTaskList.DataSource = GetContentSubmissionSelect;
            dgTaskList.CurrentPageIndex = pageIndex;
            dgTaskList.DataBind();
        }
        else
        {
            dgTaskList.Visible = false;
            lblNoContent.Visible = true;
        }
    }

//handle the page index changed
    protected void dgTaskList_PageIndexChanged(object sender, DataGridPageChangedEventArgs e)
    {
        LoadContent(e.NewPageIndex);
    }

SQL Stored Procedure
We need to have two query where one to get the number of records and the other one is to get the actual result it self
To get the query/actual result

CREATE PROCEDURE uspContentSubmissionSelect
(
	@statusID int = NULL,
	@PageIndex int,
	@PageSize int
)
AS
	SET NOCOUNT ON;
SELECT
	o.Id, o.ContentSubmission_id, o.AppointmentId,
	o.Title, o.StatusName
FROM
	(
		SELECT
			r.ID, r.contentSubmission_id, r.AppointmentId,
			r.Title, s.StatusName,
			ROW_NUMBER() OVER (ORDER BY r.ID DESC) as RowNumber
		FROM
			MyInternet.ContentSubmissionRef r
		INNER JOIN
			MyInternet.Status s
		ON
			s.Id = r.StatusID
		AND
			((@StatusID IS NULL) OR (s.ID = @statusID))
	) o
WHERE
	o.RowNumber BETWEEN (@PageIndex * @PageSize + 1) AND ((@PageIndex * @PageSize) + @PageSize)
ORDER BY RowNumber
GO


To get the record count

CREATE PROCEDURE [dbo].[uspContentSubmissionCount]
(
	@statusID int = NULL
)
AS
	SET NOCOUNT ON;

		SELECT
			COUNT(*) AS TotalRow
		FROM
			MyInternet.ContentSubmissionRef r
		INNER JOIN
			MyInternet.Status s
		ON
			s.ID = r.StatusID
		AND
			((@StatusID IS NULL) OR (s.ID = @statusID))

Page 13 of 19

Powered by WordPress & Theme by Anders Norén