I'm pretty new to SharePoint Web Part development, so I'm not sure the best practices for handling data persistence. In my application, user postbacks will be modifying some underlying data structure that I would like to maintain rather than rebuild.
The two things I have tried so far are making objects serializable, and storing them in the session array. It seems like there should be a more elegant solution though. I have also tried using custom properties where I set the web browsable attribute to false... although I haven't tried using it for custom classes.
What is the preferred method for data persistence in webparts?
Edit: Here is an example of what I think you are suggesting. First, a class
[Serializable]
public class foo
{
public foo()
{
}
}
Then in my webpart, I would have something like...
public class WebPart : WebControls.WebParts.WebPart
{
[WebBrowsable(false)]
[WebPartStorage(Storage.Personal)]
public foo bar { get; set; }
}
The next problem I seem to have is these values don't seem to persist if I change them programatically. Anything that I expose to the user through the property panel will persist only if the user makes the change. Am I missing something?
You should take a look: ASP.NET Web Parts Overview and Web Parts Personalization Overview. I personally store webparts configuration by using WebPartStorage attribute on public properties from my webpart class.
By default, sessions are disabled on Sharepoint. You should take extra care if you plan to enable it, including performance and stress tests.
Related
I have a requirement to make our current web application configurable based on client profile. So basically, allowing the application to scale and customize itself based on who the customer is. My current requirement to start off with will be simple, which is to make text within the web application configurable. So ATM, there will be 2 possible profiles, and based on which profile you select (either through AppSetting or database), all labels need to render accordingly. I can think of many ways of doing this. One thing I don't want to do is storing the label values in a database table because ATM there is no requirement to modify the labels through an interface, so I was thinking perhaps Resource files?
Also, my next requirement will be to all features within the website to be turned on/off based on profile, so I Need to keep this into consideration. Sometimes a feature will share 90% of the logic, so it wouldnt be feasible to duplicate to the feature and make the 10% changes for that profile and then have 2 copies of the same feature with minimum differences. So I'm looking for a solution for this as well. Perhaps an overall design that would cover both requirements?
Any advice will be highly appreciated.
Thanks
According to my understanding you need to update labels in the website and provide some features based on the profile selected.
So to do this , I would like to do this:
First implement MVC pattern, where our website will be in View , Model will be the Profile class and controller will host all the business logic.
If we don't want to use Database, we can serialize the object of Profile class and store (for ref
), in that we can have a File object which is a config file, where we can store the names of the features available to that profile.
At run time read all the features available for that profile and hence populate the view(website). This can be done by using either Inversion of Control Pattern. Like this:
public interface IFeatures{...}
public class Feature1 implements IFeatures{...}
public class Feature2 implements IFeatures{...}
public class Profile{
private String name;
private String pwd;
private File configFile;
...
}
public class Controller{
public List<?> getFeauturesForProfile(Profile p){
List<IFeatures> features;
List<String>feautures = scanConfigFileForFeatures(p.getConfigFile());
for(String feature : features)
features = Class.forName(feature).newInstance();
return features
}
}
Since I'm familiar with only java , I have written the syntax-es in java .
I have a WCF service using basicHttpBinding. On a service method I have a class that is returned, for this class I need to dynamically / programmatically exclude properties and change property names for the XML. This needs to be done both in the WSDL and when the service method is called.
I have searched for the best solution and it seems that I will need to (1) use the XmlAttributeOverrides with the XmlSerializer or (2) implement the IXmlSerializable on the class that needs to be customized. Or there may be a better solution altogether. I know that Property Name + "Specified" can be added to the class and then those properties can be excluded. However, this does not exclude in the WSDL and this doesn't solve the property renaming issue.
Why do I want this? Because of globalization and customization of our application. There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
After MUCH research I the best option is to swap out the WCF serializer with my own custom serializer. However, I never found good examples of how to do this for a custom class that would use the XmlSerializer. Also I'm not sure how I would pass in the XmlAttributeOverrides for a specific class.
Also, this might not be the case for others who want this same functionality but in my application I only need to initialize the values once for the lifetime of the app. Too bad C# doesn't allow static readonly variables to be used with attributes.
Here is an simple example of a class:
public Customer
{
public string Address1
{
get;
set;
}
public string Address2
{
get;
set;
}
public string Zipcode
{
get;
set;
}
}
In this example I would like to for certain installations of the application use PostalCode instead of Zipcode and hide the Address2 property.
Your help is very much appreciated.
Thanks,
Tyler
There are many properties that are built into our application that may be renamed or hidden entirely from users of the application.
A standard approach is to create a special Data Transfer Object (DTO). Or several.
I know this seems like a bit of a cop out, but since your object property names are dynamic why not just use property bagging instead of doing this XMLSerializer shuffle?
I have a two part application. One part is a web application (C# 4.0) which runs on a hosted machine with a hosted MSSQL database. That's nice and standard. The other part is a Windows Application that runs locally on our network and accesses both our main database (Advantage) and the web database. The website has no way to access the Advantage database.
Currently this setup works just fine (provided the network is working), but we're now in the process of rebuilding the website and upgrading it from a Web Forms /.NET 2.0 / VB site to a MVC3 / .NET 4.0 / C# site. As part of the rebuild, we're adding a number of new tables where the internal database has all the data, and the web database has a subset thereof.
In the internal application, tables in the database are represented by classes which use reflection and attribute flags to populate themselves. For example:
[AdvantageTable("warranty")]
public class Warranty : AdvantageTable
{
[Advantage("id", IsKey = true)]
public int programID;
[Advantage("w_cost")]
public decimal cost;
[Advantage("w_price")]
public decimal price;
public Warranty(int id)
{
this.programID = id;
Initialize();
}
}
The AdvantageTable class's Initialize() method uses reflection to build a query based on all the keys and their values, and then populates each field based on the database column specified. Updates work similarly - We call AdvantageTable.Update() on whichever object, and it handles all the database writes. It works quite well, hides all the standard CRUD, and lets us rapidly create new classes when we add a new table. We'd rather not change it, but I'm not going to entirely rule it out if there's a solution that would require it.
The web database needs to have this table, but doesn't have a need for the cost data. I could create a separate class that's backed by the web database (via stored procedures, reflection, LINQ-TO-SQL, ADO data objects, etc), but there may be other functionality in the Warranty object which I want to behave the same way regardless of whether it's called from the website or the internal app, without the need to maintain two sets of code. For example, we might change the logic of how we decide which warranty applies to a product - I want to need to create and test that in only one place, not two.
So my question is: Can anyone think of a good way to allow this class to sometimes be populated from the Advantage database and sometimes the web database? It's not just a matter of connection strings, because they have two very different methods of access (even aside from the reflection). I considered adding [Web("id")] type tags to the Advantage tags, and only putting them on the fields which exist in the web database to designate its columns, then having a switch of some kind to control which set of logic is used for reading/writing, but I have the feeling that that would get painful (Is this method web-safe? How do I set the flag before instantiating it?). So I have no ideas I like and suspect there's a solution I'm not even aware exists. Any input?
I think the fundamental issue is that you want to put business logic in the Warranty object, which is a data layer object. What you really want to do is have a common data contract (could be an interface in this case) that both data sources support, with logic encapsulated in a separate class/layer that can operate with either data source. This side-steps the issue of having a single data class attempt to operate with two different data sources by establishing a common data contract that your business layer can use, regardless of how the data is pulled.
So, with your example, you might have an AdvantageWarranty and WebWarranty, both of which implement IWarranty. You have a separate WarrantyValidator class that can operate on any IWarranty to tell you whether the warranty is still valid for given conditions. Incidentally, this gives you a nice way to stub out your data if you want to unit test your business logic in the WarrantyValidator class.
The solution I eventually came up with was two-fold. First, I used Linq-to-sql to generate objects for each web table. Then, I derived a new class from AdvantageTable called AdvantageWebTable<TABLEOBJECT>, which contains the web specific code, and added web specific attributes. So now the class looks like this:
[AdvantageTable("warranty")]
public class Warranty : AdvantageWebTable<WebObjs.Warranty>
{
[Advantage("id", IsKey = true)][Web("ID", IsKey = true)]
public int programID;
[Advantage("w_cost")][Web("Cost")]
public decimal cost;
[Advantage("w_price")][Web("Price")]
public decimal price;
public Warranty(int id)
{
this.programID = id;
Initialize();
}
}
There's also hooks for populating web-only fields right before saving to the web database, and there will be (but isn't yet since I haven't needed it) a LoadFromWeb() function which uses reflection to populate the fields.
I am building a library to automatically create forms for Objects in the project that I am working on.
The codebase is in C#, and essentially we have a HUGE number of different objects to store information about different things. If I send these objects to the client side as JSON, it is easy enough to programatically inspect them to generate a form for all of the properties.
The problem is that I want to be able to create a simple way of enforcing permissions and doing validation on the client side. It needs to be done on a field by field level.
In javascript I would do this by creating a parallel object structure, which had some sort of { permissions : "someLevel", validator : someFunction } object at the nodes. With empty nodes implying free permissions and universal validation. This would let me simply iterate over the new object and the permissions object, run the check, and deal with the result.
Because I am overfamilar with the hammer that is javascript, this is really the only way that I can see to deal with this problem. My first implementation thus uses reflection to let me treat objects as dictionaries, that can be programatically iterated over, and then I just have dictionaries of dictionaries of PermissionRule objects which can be compared with.
Very javascripty. Very awkward.
Is there some better way that I can do this? Essentially a way to associate a data set with each property, and then iterate over those properties.
Or else am I Doing It Wrong?
It sounds like you are describing custom attributes - i.e.
[Permissions("someLevel"), Validator("someFunction")]
public string Foo {get;set;}
This requires some reflection to read the attributes, but is quite a nice way of decorating types / members / etc. You might also look at the pre-rolled [PrincipalPermission] for security checks. Is this what you mean?
Note the above would require:
public class PermissionsAttribute : Attribute {
private readonly string permissions;
public string Permissions { get {return permissions;}}
public PermissionsAttribute(string permissions) {
this.permissions = permissions;
}
}
(and similar for the other)
You can read them out with Attribute.GetCustomAttributes
I have a set of functions I want to be available to my web pages and user controls in my c# .net 3.5 web project. My standard approach for pages is to create a "base page" that extends the System.Web.UI.Page class and then have my pages inherit from this, rather than directly from the Page class.
I now want to expose some of these functions to my web controls (ascx) and web services. I can think of a number of ways to do this, but they seem a little clumsy and I think I'm missing a trick.
Is there an easy way to provide some common functions to both my pages, web services and controls using inheritance, or do I need to wrap these functions in a class that all of them can access?
An example to clarify:
I have a singleton that handles most functionality for my web application.
At the start of each request I want to check that the class exists in the web cache and initialise it if not.
Initially this was handled in a page base that the pages all used. Now I need to be able to access my singleton safely from services and controls, with the same checks. I have therefore extracted the checking and initialisation logic into another class, that then each of my base page, control and web service, all instantiate. Even with this model I have the same code repeated in 3 places (each of my base classes for controls, ws and pages), albeit not much code, this seems wrong too!
It works, but it seems clumsy...I look forward to you guys humbling me with your wisdom!
Sounds to mee like a case of aspect-oriented programming. .NET is ill equipped for this. I'm afraid that your solution is one of the best.
Alternatively perhaps you can move all or some of those functions to a static class/singleton and then use that class from your aspx/ascx/asmx? Not much in the way of inheritance, but at least less code duplication.
My solution to this is to put all the methods and functions I want to share in my base master page class. I then put an equivalent for each method and function in the user control base class as follows:
//Property in masterpage base
public string QsSearchTerm
{
get
{
if (!String.IsNullOrEmpty(Request.QueryString["q"]))
{
return Helpers.SanitiseString(Server.UrlDecode(Request.QueryString["q"]));
}
return String.Empty;
}
}
//Property in usercontrol base
public string QsSearchTerm
{
get
{
if (Page.Master is BaseMasterPage)
{
return ((BaseMasterPage)Page.Master).QsSearchTerm;
}
return string.Empty;
}
}
What this doesn't help with, is your code repetition with web service base classes. I would think that refactoring the above into a class with a constructor that accepts an HttpContext instance would be the way forward. You can then expose a singleton instance of this class in your base web service, master page, user control, page etc.
Hope this helps, but I too would be interested in hearing if there's a better way.
In your Singleton you could provide a Strategy interface to allow variations of the code depending on the configured environment. This would allow you to switch between web/windows/wcf...and so on.
I think using a BasePage is the right approach.
I have multiple base pages and custom user controls that load differently depending on which basepage is used by the current page.
In your custom user control you can use something like:
if (this.Page is BasePageName)
{
BasePageName bp = (BasePageName)this.Page;
bp.BasePageFunction();
}
No you can get ride of the repetitive code in the custom user control and just call it from the base page.
You can also have a hierarchy of inherited base pages depending on page functionality and needs. ie.) BasePageName2 : BasePageName