Tuesday, April 1, 2014
Friday, August 27, 2010
Infopath Performance tips #2
In my last post, I mentioned that I'd recently gone through one of my forms and identified several causes of slow performance. I was able to reduce the form's load time from 40 to 2 seconds. Most of that performance gain came from moving file attachments outside the form for storage. I'll be talking about how I did that in my next post.
Today I'm going to talk about Web Service calls. When I was testing my load times, I found that even the quickest web service call took at least 0.5 seconds. Since my form originally had 7 such calls, that time was really stacking up. I went through my form and eliminated all my Web Service calls that were being called during the On Load event. :
First, I replaced Web Service calls with native APIs whenever possible. For example, I was pulling in information about the current user using the Sharepoint User Profile web service. I replaced this with a call to the User Profile Manager. Here's a snippet where I get the user's Department:
ServerContext context = ServerContext.GetContext(myWeb.Site);
UserProfileManager upMgr = new UserProfileManager(context);
UserProfile currentProfile = upMgr.GetUserProfile(loginName);
departmentField.SetValue(currentProfile["Department"].toString());
Some Web Service calls just can't be replaced...so I hid them. For instance, on my form I was contacting our financial system and pulling in the latest budget numbers. This information needed to appear on my form, and the web service was the only way to get at that information. What I did was move the budget information off the default view and put it on a new budget view instead.
That eliminated the need to populate the information on the form load. My form already uses Button Tabs to move between views. All I had to do was add my Web Service call to the budget tab. That way the budget web service doesn't get called until it is needed. The user doesn't notice the slight delay because the page is being redrawn.
You could use the same approach with a hidden section that is displayed by clicking on a button, or selecting a radio option.
Today I'm going to talk about Web Service calls. When I was testing my load times, I found that even the quickest web service call took at least 0.5 seconds. Since my form originally had 7 such calls, that time was really stacking up. I went through my form and eliminated all my Web Service calls that were being called during the On Load event. :
First, I replaced Web Service calls with native APIs whenever possible. For example, I was pulling in information about the current user using the Sharepoint User Profile web service. I replaced this with a call to the User Profile Manager. Here's a snippet where I get the user's Department:
ServerContext context = ServerContext.GetContext(myWeb.Site);
UserProfileManager upMgr = new UserProfileManager(context);
UserProfile currentProfile = upMgr.GetUserProfile(loginName);
departmentField.SetValue(currentProfile["Department"].toString());
Some Web Service calls just can't be replaced...so I hid them. For instance, on my form I was contacting our financial system and pulling in the latest budget numbers. This information needed to appear on my form, and the web service was the only way to get at that information. What I did was move the budget information off the default view and put it on a new budget view instead.
That eliminated the need to populate the information on the form load. My form already uses Button Tabs to move between views. All I had to do was add my Web Service call to the budget tab. That way the budget web service doesn't get called until it is needed. The user doesn't notice the slight delay because the page is being redrawn.
You could use the same approach with a hidden section that is displayed by clicking on a button, or selecting a radio option.
Wednesday, August 25, 2010
Infopath Performance tips #1
In the next few posts I'm going to share some of my experiences with Infopath performance tuning. Recently I took a look at one of my earliest forms to try to improve performance.
The form in question was taking around 20 seconds to load when new, and up to 40 seconds to load when loaded with data. Obviously, this was not acceptable. I did a code review and got the load time down to a consistent 2 seconds.
Here's what I found:
1) Web Service calls are sloooooow. That includes calls to Web Services on the Sharepoint server for things like User Profiles.
2) File Attachments = Death. Any file that you attach to your Infopath form is stored as encoded text within your form. That means if you have a 5MB Word Document attached, your Infopath document is suddenly 5MB bigger. That leads to:
3) Post Back events make your form look slow. This is because every time you fire a post-back event, a copy of your form is uploaded to the server...your action is performed...and an updated version of your form is downloaded from the server. If your form is full of attachments, you can imagine how slow this can become. Even if your form isn't large, you're still looking at a half-second during which your form is locked up.
The fixes I implemented on my form were:
1) Get rid of all Web Service calls. Those Web Service calls I couldn't eliminate I hide by putting them into View Changes when the user is already expecting a short wait. I eliminated all Web Service calls from my On-Load events.
2) Move file attachments outside your form. All my attachments are now stored in a separate Document Library. My Infopath form contains links to the files which are displayed to the user as clickable links.
3) Combine multiple Post Back events instead of firing them one at a time. I did this by using Views to create a Wizard type interface. Users select several Radio Button options but my post back doesn't fire until they click a Next button at which point I do all my processing at once.
In my following posts I'll give examples for each, including the code I'm using. First up will be how I replaced my call to the User Profile web service.
The form in question was taking around 20 seconds to load when new, and up to 40 seconds to load when loaded with data. Obviously, this was not acceptable. I did a code review and got the load time down to a consistent 2 seconds.
Here's what I found:
1) Web Service calls are sloooooow. That includes calls to Web Services on the Sharepoint server for things like User Profiles.
2) File Attachments = Death. Any file that you attach to your Infopath form is stored as encoded text within your form. That means if you have a 5MB Word Document attached, your Infopath document is suddenly 5MB bigger. That leads to:
3) Post Back events make your form look slow. This is because every time you fire a post-back event, a copy of your form is uploaded to the server...your action is performed...and an updated version of your form is downloaded from the server. If your form is full of attachments, you can imagine how slow this can become. Even if your form isn't large, you're still looking at a half-second during which your form is locked up.
The fixes I implemented on my form were:
1) Get rid of all Web Service calls. Those Web Service calls I couldn't eliminate I hide by putting them into View Changes when the user is already expecting a short wait. I eliminated all Web Service calls from my On-Load events.
2) Move file attachments outside your form. All my attachments are now stored in a separate Document Library. My Infopath form contains links to the files which are displayed to the user as clickable links.
3) Combine multiple Post Back events instead of firing them one at a time. I did this by using Views to create a Wizard type interface. Users select several Radio Button options but my post back doesn't fire until they click a Next button at which point I do all my processing at once.
In my following posts I'll give examples for each, including the code I'm using. First up will be how I replaced my call to the User Profile web service.
Friday, August 13, 2010
Relink Infopath Documents Web Part
We've been archiving our old documents lately, and we usually do this by moving old Infopath documents to an archive Site. When you do this, you need to relink the Infopath documents to the new Site Collection.
Microsoft gives you a tool to do this, the Relink Documents view that's on every Form Library. The problem with this is that you have to select each document manually, and you're limited to 100 documents at a time. There are hacks out there that help with both of these problems, but I wanted something better.
After some searching, I found this project: http://sprelinkdocuments.codeplex.com/ This is a Windows app that can be run on the server. The app asks you for the GUID of the form library. The creator of the script helpfully provided his source code, so I took that and wrapped it in a Web Part.
When you add the Web Part to your site, it checks the URL of the hosting page to see if it is on the Relink view page. If it is, it parses the URL of the page to figure out the name of the Form Library. If it isn't on the Relink view page, it just shows a drop-down menu with a list of all the Form Libraries on the site.
I've forwarded a copy of my source to the owner of the original project. It should be posted to the Codeplex site soon.
Microsoft gives you a tool to do this, the Relink Documents view that's on every Form Library. The problem with this is that you have to select each document manually, and you're limited to 100 documents at a time. There are hacks out there that help with both of these problems, but I wanted something better.
After some searching, I found this project: http://sprelinkdocuments.codeplex.com/ This is a Windows app that can be run on the server. The app asks you for the GUID of the form library. The creator of the script helpfully provided his source code, so I took that and wrapped it in a Web Part.
When you add the Web Part to your site, it checks the URL of the hosting page to see if it is on the Relink view page. If it is, it parses the URL of the page to figure out the name of the Form Library. If it isn't on the Relink view page, it just shows a drop-down menu with a list of all the Form Libraries on the site.
I've forwarded a copy of my source to the owner of the original project. It should be posted to the Codeplex site soon.
Monday, August 9, 2010
New Tool Created - Group Synch
I just posted a new tool on the CodePlex this afternoon. Here's a lin: http://spgroupsynch.codeplex.com/
The tool synchronizes groups between Site Collections in Sharepoint. You show it a Site Collection to start from, it pulls all the Groups and Group Membership and then copies it over to another Site Collection. It's a one-way push only, although you could get that if you run the tool again with the To and From sites reversed now that I think about it.
I wrote the tool over the weekend because my manager was worried about the ability to get our custom workflows running on multiple site collections. Our workflows use Group Memberships to control access to forms and assign tasks...and we have literally thousands of them. Basically every job title at every location gets a group, eg Corporate CEO, HospitalA CFO, etc. Trying to keep all these groups up to date is already a daunting task in our single site collection. Just thinking of maintaining multiple copies of these groups updated across a couple dozen site collections was giving me nightmares.
This was a fun little script to write. I used the basic framework that I originally came up with building my SPWakeup app. This handles things like Logging, Run-Time options, etc. In this version I replaced asking for a mail server IP at runtime and used the SPUtility.Sendemail() instead. It's a much cleaner way to handle mail, and should avoid some time-out issues I've been having with our internal mail server.
This is also the first time I've really taken advantage of Class constructors. In the past I'd just been createing my class object, and then manually setting the properties. This has been a silly way to do things, so I forced myself to work with constuctors on this project. I'm very happy with the results.
I think I can also say that I've finally gotten a real handle on working with SPGroup and SPUser objects. I've been working a great deal with Permissions lately, so I've been knee-deep in SPMembers for the last few months. When I was writing this tool, I actually wrote all the major functions without ever debugging or building. When I launched it for the first time this afternoon, I was really pleased that everything worked the way I expected it to the first time.
Subscribe to:
Posts (Atom)