Wednesday, March 25, 2009

Determining an object size in C#

I am implementing business logic for a web application that will result in a sizeable data structure being housed in a class. I may decide to cache the class in the session at some point and I wanted to know how much RAM the class takes up. To figure that out, the best way I could find (here) was to serialize it and determine the size of the resulting binary. Of course the entire class (and any classes it holds as public properties) needs to be serializable.



long lSize = 0;
System.IO.MemoryStream stream = new System.IO.MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter objFormatter =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
objFormatter.Serialize(stream, this.SalesOrder);
lSize = stream.Length;
output.Write("Size of the Object: " + lSize.ToString());

Wednesday, February 18, 2009

Creating a Matrix form in Dynamics NAV

I have always just copied matrix forms and hacked them up to create a new one.  Today, after developing in NAV since it was called Avista in 1996, I created one from scratch.  Here are the steps (sorry there are no images, maybe later):

Create a New, blank form, set the SourceTable of the form to the record to be used as the rows in the matrix.  Add any columns you want on each row to the left of the matrix using the Field Menu.

Create 2 text values: MatrixValue, and MatrixHeader.

Put a Matrix control on the form, assign the MatrixSourceTable to be the record defining the columns of the matrix.

If the form is to be focused on another record (like a matrix of sizes and colors for a single item), you can create a function used to open the form, create the record as a global variable and get the source record in that function.

Add a text box to the right section of the matrix, set the sourceexpression to MatrixValue.
Add a text box to the header portion of the new column, set the sourceexpression to MatrixHeader

If the matrix rec (the record defining the number of columns in the matrix) is bound to the source rec, call 

On form open, set filter on the SourceTable variable, using the source record, changing to filter group 2 before, and then 0 afterward, then filter the MatrixSourceTable if needed as follows:

CurrForm.Matrix.MatrixRec.SETRANGE("Field",SourceTable."Field");

Select the entire Matrix control, and in the Matrix-OnAfterGetRecord() trigger:

MatrixHeader := CurrForm.Matrix.MatrixRec."Field";

Or any other value.  In my case, I appended the code with the description since the users needed both.

Select the right portion of the Matrix control and go to the C/AL code.

In the OnFormat section assign the text to whatever you want displayed in each grid box, using the Currform.Matrix.MatrixRec to determine the Column, and the SourceTable for the row, and the SourceRecord if needed.

That's it!



Tuesday, January 27, 2009

Resetting password with asp.net security

When using hashed passwords, if a user forgets their password, there is no obvious way to reset it, since the old password is needed to assign a new password, and hashed passwords can not be retrieved from the database, the but it can be done.

The key is to reset the password first, then use the reset password to create a new password entered by the administrator.

I put a couple textboxes up on a page (tbPassword and tbConfirmPassword) and in the Web.Config set the requiresQuestionAndAnswer property of the security provider to false.

With that in place, if the administrator puts a value in the "New Password" text box, I know they intend to change the password and call the following code:



if (tbPassword.Text != "")
{
string tempPassword = Membership.Provider.ResetPassword(membershipUser.UserName, "");
Membership.Provider.ChangePassword(membershipUser.UserName, tempPassword, tbPassword.Text);
}

AJAX and browser cache

When using AJAX to update a page, if the user leaves the page and comes back via the back button, the content will revert to the values the page had when it initally loaded.  To remove that behavior the following c# code will force a refresh from the server and display the page based on the latest information on the server.

Response.Buffer = true;
Response.ExpiresAbsolute = DateTime.Now;
Response.Expires = 0;
Response.CacheControl = "no-cache";
Response.Cache.SetNoStore();

Thursday, January 22, 2009

Modifying a table in SQL 2008 Mgt Studio

When adding a field or making other changes that requires a table be dropped and re-added, you may receive an error like 

"Saving changes is not permitted. The changes you have made require the following tables to be dropped and re-created. You have either made changes to a table that can't be re-created or enabled the option Prevent saving changes that require the table to be re-created."

If that happens, you need to update the management studio options as described here.

Wednesday, January 14, 2009

ToString()

I am always forgetting how to use ToString() to get things formatted the way I want them.

To format a datetime as a date:

RequestedShipDate.ToString("d");

RequestedShipDate.ToString("MM/dd/yyyy");

Wednesday, December 31, 2008

Log in to web service programatically

Web service calls that are exposed to the public but which you don't want open to public calls can be secured using directory security on the directory IIS uses. This is only a valid method if the call is made over a controlled network since basic authentication password can be snooped.

Microsoft has a great page on how to use it, so I will only summarize

NavCustomer.CustomerService navCustService = new NavCustomer.CustomerService();
CredentialCache credentialCache = new CredentialCache();
NetworkCredential credentials = new NetworkCredential(
ConfigurationSettings.AppSettings["WebServiceUserName"],
ConfigurationSettings.AppSettings["WebServicePassword"],
ConfigurationSettings.AppSettings["WebServiceDomain"]);
credentialCache.Add(new Uri(navCustService.Url), "Basic", credentials);
navCustService.Credentials = credentialCache;