Monday, December 19, 2005

Loading User Controls into Web Parts

Create Google.ascx as a web part article demonstrates how to create User Control and insert it into Web part.
Tip from the article: in order to get rid of "Untitled" header in Web part - define title attribute for user control:
<uc1:Google title="Google Search" runat="server" ID="Google1" />


Personalize Your Portal with User Controls and Custom Web Parts article demonstrates how to bind User Control to Web Part dynamically:
// create Web Part instance from User Control file
Control uc = this.LoadControl(@"webparts\CompanyNews.ascx");
uc.ID = "wp2";
GenericWebPart wp2 = WebPartManager1.CreateWebPart(uc);
WebPartManager1.AddWebPart(wp2, WebPartZone1, 1);

Tuesday, December 13, 2005

Web Site Administration Tool for ASP.NET 2.0 / VS.NET 2005

I looked into "Web Site Administration Tool" source code... It's pretty messy.
Variables have senseless names, code is complex, a lot of unnecessary code, grids are binding 2 times, ...

No wonder that "Web Site Administration Tool" is sluggish and bug-prone.
Moreover, such code is very hard to fix (you fix one bug and getting 2 bugs instead).
I think either Microsoft would either rewrite this tool from scratch or leave as it is.

See also: discussion in microsoft.public.vsnet.general

Monday, November 21, 2005

Large Data Operations in SQL Server

Large Data Operations in SQL Server

This article explains how performance is affected by choosing "table scan" or "index seek". Also it shows how memory available for SQL Server affects performance.

MS SQL Server 2000.

Monday, November 14, 2005

Interview questions

1) What do you know about this project?
2) What states did you work in?
3) What did you do in your project?
4) What did you complete in your project?
5) How would you create report page?
6) What interesting SP did you write?
7) How would you select 50 states with CA on top?
8) How would you get all records from table A which don’t have matches in table B?

Thursday, November 10, 2005

Bayden Systems - IEToys

Bayden Systems - IEToys
Tools for Internet Explorer:
- Image cleanup.
- Define & Dictionary.
- Partual HTML source.
- Word Highlighter.
- Access keys.

Fiddler HTTP Debugger

If you want to trace what HTTP get/post requests your browser prepares, and trace HTML response which web server returns to your browser --- use Fiddler HTTP Debugger

Thursday, November 03, 2005

How to deal with users/roles/permissions

Typical business application with many clients works with many users. These users are linked to groups. These groups could be linked to other groups. There could be recursion in groups' hierarchy.
Every group has permission to access some business components.

Typical task in the application would be to figure out if specified user has right to access specified business component. Let's refer this task as "access question".
We want to answer this "access question" as fast as possible, because "access question" would be asked every time when user accesses a component.

One of the simplest approaches would be to implement standart table construction like:
User - Role - Permission.
But that may be not flexible enough from business perspective.
Example: Sometimes business wants to add user JohnDoe, who is employee of company Company1 to role Company1Role.
In turn Company1Role belongs to ReportViewersRole.
And ReportViewersRole has permission to access "Reports" components.
This example would not fit into simple "User - Role - Permission" model.


So, what's the solution?

The two approaches below look more viable than others:


Approach #1. Limited hierarchy of roles.

Most probably this approach would have short chain of links:
User <-> User roles <-> Permissions roles <-> Permissions

Because of limited number of links in the chain, answering question “is this user has permission to access this component?” would be pretty fast.

"Limited hierarchy of roles" approach would cover 90+% or use cases. If this approach covers close to 100% of use cases we should use this approach, because it’s simpler than Approach #2.


Approach #2. "Permissions datawarehouse"

This approach can adopt unlimited hierarchy/recursion of roles and still work pretty fast.

The idea is to have two sets of tables.

First set would have the following tables:
Users
Roles
RolesRecursiveHierarchy
RolesPermissions
and optionally - Permissions table.

This First set is responsible for maintaining permissions hierarchy (adding/deleting users, adding/deleting roles, defining roles permissions, defining roles hierarchy).

This First set would not be responsible for answering question: "is this user has permission to access this component?". The First set is too slow for that: ~ 1 ... 10 seconds.

That why we would need second set. Exactly for answering this permission question.

The second set consists of only one table:
UserPermissions

UserPermissions table keeps pre-calculated information from the First set. UserPermissions directly links every user to corresponding set of permissions.

Every record would consist of 2 integer fields (UserId, PermissionId).

If we estimate to have ~10000 users, and estimate that average user would have ~500 permissions, then UserPermissions table would have ~5 million records.

Answering the question ("is this user has permission to access this component?") would be implemented in form of SQL query:
Exists(Select 1 from UserPermissions where UserId = @UserId and PermissionId = @PermissionId)

Because UserPermissions would be indexed --- the query would be pretty fast.

Every time when the First Set is updated, The Second set would be updated too.

Note 1:
Another implementation of The Second set could be: User_PermissionRole table.
Difference between User_PermissionRole and UserPermissions is that if UserPermissions caches chain of N links, User_PermissionRole would cache chain of (N-1) links. Last link would be implemented in C# components code.

Note 2:
We can cache "The Second set" in memory. It would be ~100 Megabyte.


Bottom line:

Approach #2 is more flexible, but more technically challenging than Approach #1.

If Approach #1 ("Limited hierarchy of roles") works good enough – we’d better use it.

If Approach #1 does not cover enough use cases --- we’d better use Approach #2 ("Permissions datawarehouse").

Sunday, October 30, 2005

Regular Expression Quick Start

Regular Expression Quick Start
I like it --- way better than MSDN's RegEx "tutorial".

Tuesday, October 18, 2005

Connection string in ASP.NET 2.0 application

It is a good idea to put connection string into connectionStrings section of Web.Config:
<connectionStrings>
<add name="MyConnectionString" connectionString="Integrated Security=SSPI;Initial Catalog=pubs;Data Source=(local);"/>
</connectionStrings>

Then you can easily read it from your application:
string connectionString = System.Web.Configuration.WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;

If you want to encrypt your connectionStrings section:
1) Copy Web.Config file into C:\Inetpub\wwwroot\MyWebSite folder.
2) Execute the following command:
C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_regiis.exe -pe "connectionStrings" -app "/MyWebSite" -prov "DataProtectionConfigurationProvider"

If command from #2 was successfully executed, your ConnectionStrings section in C:\Inetpub\wwwroot\MyWebSite\Web.Config file is encrypted.
You still can use the same command in order to access your connection string:
System.Web.Configuration.WebConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString;


VS.NET 2005, C#, ASP.NET 2.0

Tuesday, October 11, 2005

How to ignore DTD validation

Question:


When I'm trying to load XML into XmlDocument:
xmlDocument.Load(memoryStream);
or deserialize XML:
XmlSerializer reader = new XmlSerializer(responseType);
object response = reader.Deserialize(xmlReader);

I'm getting an error:
Could not find file 'C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\MySchema.dtd'

The problem is the "MySchema.dtd" is referred in XML string/stream which I’m trying to load:
-------- XML string ------


------------------------------
I have MySchema.dtd, but I don’t want to deploy it into .NET folder “'C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\”

How could I specify folder where Xml parser should look for DTD schemas?

Or at least how to tell XML parsers to ignore DTD validation comletely?

Solution


You may try couple of solutions:
1) Turn off DTD validation completely.
That’s simple: just set XmlResolver property to null:
xmlDocument.XmlResolver = null;
or:
xmlReader.XmlResolver = null;
2) Specify your folder where you store your DTD schemas.
In order to implement it you have to create custom XmlResolver class, that is derive this custom class from XmlResolver, or even better from XmlUrlResolver.
Then override ResolveUri and/or GetEntity methods.
Overridden ResolveUri has to return absolute path to your DTD storage folder.
Last step would be instantiate your custom class and set XmlResolver property:
xmlDocument.XmlResolver = new MyCustomXmlUriResolver();

-------
Example/Examples/Sample for Visual Studio .NET 2005, C# 2.0, ASP.NET 2.0
System.Xml namespace

Tuesday, September 20, 2005

ASP.NET 2.0 Page Lifecycle methods

Source:
ASP.NET 2.0 Internals


MethodActive
ConstructorAlways
ConstructAlways
TestDeviceFilterAlways
AddParsedSubObjectAlways
DeterminePostBackModeAlways
OnPreInitAlways
LoadPersonalizationDataAlways
InitializeThemesAlways
OnInitAlways
ApplyControlSkinAlways
ApplyPersonalizationAlways
OnInitCompleteAlways
LoadPageStateFromPersistenceMediumPostBack
LoadControlStatePostBack
LoadViewStatePostBack
ProcessPostData1PostBack
OnPreLoadAlways
OnLoadAlways
ProcessPostData2PostBack
RaiseChangedEventsPostBack
RaisePostBackEventPostBack
OnLoadCompleteAlways
OnPreRenderAlways
OnPreRenderCompleteAlways
SavePersonalizationDataAlways
SaveControlStateAlways
SaveViewStateAlways
SavePageStateToPersistenceMediumAlways
RenderAlways
OnUnloadAlways

Friday, September 16, 2005

Friday, June 24, 2005

How to fix problem with access to application log from ASP.NET

How to fix problem with access to application log from ASP.NET
If you get error:
"Requested registry access is not allowed"
during "EventLog.WriteEntry" operation, then do this:
1) Create win application which will create Event Source for application log:
EventLog.CreateEventSource
Example:
=====
private void TestForm_Load(object sender, System.EventArgs e)
{
System.Diagnostics.EventLog.CreateEventSource("LogName", "Application");
}
=====

2) You must have Administrator's privileges on the computer which will be used as Web Server (your ASP.NET code will log into Application log of this computer).
3) Execute "EventLog.CreateEventSource" piece of code.
4) Your Web-application must use only this "LogName" source in "EventLog.WriteEntry" method call.

Thursday, June 23, 2005

SMTP Authentication in ASP.NET

Do you want to send email in ASP.NET and your SMTP server requires SMTP authentication?

Here is the code to do that:
=======================
public static void SendMail(
string mailTo,
string mailFrom,
string mailSubject,
string mailBody,
string mailCc,
string mailBcc,
string smtpServer,
string userName,
string password)
{
System.Web.Mail.MailMessage mailMessage = new System.Web.Mail.MailMessage();
mailMessage.From = mailFrom;
mailMessage.To = mailTo;
mailMessage.Subject = mailSubject;
mailMessage.Body = mailBody;
mailMessage.Cc = mailCc;
mailMessage.Bcc = mailBcc;
mailMessage.BodyFormat = System.Web.Mail.MailFormat.Text;

const int cdoBasic = 1;
const int cdoSendUsingPort = 2;

mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", cdoBasic);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", userName);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", password);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusing", cdoSendUsingPort);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserver", smtpServer);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout", 10);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpserverport", 25);
mailMessage.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpusessl", false);

System.Web.Mail.SmtpMail.Send(mailMessage);
}
=======================

Original snippet is from here:
SMTP Authentication in ASP.NET

Friday, May 27, 2005

How to access deleted rows in .NET dataset or datatable

Scenario:


1) UserInterface.dll gets typed dataset from MiddleTier.dll.
2) UserInterface.dll modifies, inserts, and deletes several rows from the typed dataset.
3) UserInterface.dll passes modified typed dataset back to MiddleTier.dll.
4) MiddleTier.dll needs to figure out what rows were modified, inserted, and deleted, then MiddleTier.dll needs to read these rows and prepare SQL command for the database.

What can we easily do:


- We can get access to modified and inserted rows:
ds.GetChanges(DataRowState.Added);
ds.GetChanges(DataRowState.Modified);
- We can also get access to deleted rows:
tableDeleted = table.GetChanges(DataRowState.Deleted);

Where the problem is:


- As soon as we try to access deleted rows we are getting exception:
-----------
An unhandled exception of type 'System.Data.DeletedRowInaccessibleException' occurred in system.data.dll

Additional information: Deleted row information cannot be accessed through the row.
-----------

Solution:


We need to reject changes in tableDeleted:
tableDeleted.RejectChanges();


Full code:


TestDataSet ds = new TestDataSet();
TestDataSet.TestTableDataTable table = ds.TestTable;
table.Rows.Add(new object[] {1, "key1", "Test1"});
table.Rows.Add(new object[] {2, "key2", "Test2"});
table.AcceptChanges();
table.Rows[0].Delete();
TestDataSet.TestTableDataTable tableDeleted = (TestDataSet.TestTableDataTable)table.GetChanges(DataRowState.Deleted);
tableDeleted.RejectChanges();
TestDataSet.TestTableRow row = tableDeleted[0];
int deletedKey1 = row.Key1;
string deletedKey2 = row.Key2;
string deletedValue001 = row.Value001;

What helped to find the solution


Google helped me to find
this info:

By Ritesh Jain via DotNetMonster.com

There is one alternative that u can try.........

'copy all the Deleted Rows into another Tables
dim dtDeleted as Datatable

dtDeleted = dtDetail.GetChanges(DataRowState.Deleted)
dtDeleted .RejectChanges

With cmdDel
Dim dr as DataRow
For Each dr In dtDeleted.Rows '
.CommandText = "DELTE FROM Table1 WHERE Id = " & dr!Id
.ExecuteNonQuery()
Next
End With

Followers

Blog Archive

About Me

My photo
Email me: blog@postjobfree.com