I'm trying to ascertain what the best practise is for creating a SharePoint WebPart that has custom properties. I'll detail the background, because I might be doing this in completely the wrong way.
I've taken a DevExpress chart, which has a whole host of settings on there. I then decided to expose some of these settings and ended up with a WebPart that looked like:
public class MyWebPart : WebPart
{
public DataTable { get; set; }
public String ConnectionString { get; set; }
public String Query { get; set; }
public override void DataBind()
{
UpdateMyTable(ConnectionString, Query);
this.chartControl.DataSource = this.DataTable;
}
}
I needed to add a whole load more settings onto this web part, a few single items that are strings, and others that correspond to a series (e.g. Binding values, Chart Type). So I moved the settings off the WebPart and ended up with something more akin to the following:
public class MyWebPart : WebPart
{
public DataTable { get; set; }
public ChartSettings { get; set; }
public override void DataBind()
{
UpdateMyTable(ConnectionString, Query);
this.chartControl.DataSource = this.DataTable;
}
}
public ChartSettings
{
public List<SeriesSettings> Series { get; set; }
}
I made my settings classes Serializable and added a Personalizable attribute on the Property on my web part. This works fine via the web.
If I attempt to open the page in SharePoint designer however it complains that it can't create a ChartSettings (and DataTable) from their String representations. I've learnt that this is because the settings are exposed as Strings. Obviously the DataTable I can suppress the serialization of.
My question ultimately is, am I following the correct approach, moving settings onto a class? Or should I be leaving all the settings on my webpart (which would be messy keeping lots of series settings in different arrays), or is there a completely different approach? If you can point me to any references to support your suggestion (e.g. MSDN) then that would be very much appreciated.
My personal experience (and some may disagree) has been to keep the WebPart as thin as possible. WebParts seem to be awkward for things like: configuration, error handling and logging, tracing, etc. I have found it much easier to put the bulk of my development into a WS (WebService/WCF) on localhost:8080. The code in the webpart is simple: call the WS and let it do all of the work. Config in the webpart is now simple because localhost is always easy to find. Dev tools for WS/WCF are very strong. Config, debugging, error handling, logging, tracing are all much simpler in WS/WCF. Better still, I make a simple jig (Winform/Webform) to call/test my WS layer. With this architecture, you put your code where your dev tools are strongest. It is similar to the rationale behind the MVC pattern.
Related
How can I save data from a object to the browser and retrieve that data using server-side Blazor?
I have a model to filter an overview, but if you navigate away from the overview and come back the filter is gone. It's a pretty advanced filter so filling it out every time is not really an option.
Let's do this simplified example:
public class OverviewFilterModel
{
public string Keywords { get; set; }
public int PartnerId { get; set; }
public EnumStatus Status { get; set; }
}
public enum EnumStatus
{
A,
B,
C
}
How do I save above model in browser and retrieve it again? Or is there no such thing? I do not want to use an SQL database for this, or anything server-side.
You can use Blazored.LocalStorage. Its a third party library developed by Chris Sainty to store data in your browser which persists across pages and you can access that data from a new tab as well.
Just pull the library from Nuget, register the service in your Startup class, inject it into any page or component you want and then store whatever data you want in the browser local storage.
#inject Blazored.LocalStorage.ILocalStorageService localStorage
#code {
protected override async Task OnInitializedAsync()
{
await localStorage.SetItemAsync("name", "John Smith");
var name = await localStorage.GetItemAsync<string>("name");
}
}
You can add complex nested objects as well.
You can verify the data/model that you have stored in your browser local storage if you open developer options.
Here's the github repo link. You will find all the documentation here :
https://github.com/Blazored/LocalStorage
I have a very weird scenario which I can't seem to figure out what's going on. I have a web service which is written in C# and the target framework is 3.5. I have many Classes and Methods but for simplicity I will make use of only two classes in the question.
public class PathNames
{
private string _pathA = "Some Path";
private string _pathB = "Another Path";
public string BaseDirectoryPath
{
get
{
return Path.Combine(_pathA, _pathB);
}
}
}
The second class is as follows:
public class UserInformation
{
public string UserName { get; set; }
...//more properties
}
Both of the above classes are in the same namespace.
The web service is referenced in a WebForm Application with the target framework being 4.0. Everything seems to be working fine and I can see the UserInformation class when I view it in Object Browser. However the PathNames class does not seem to be visible in the Object Broswer.
Both of the source files in question are set to Compile in the File Properties windows. I have 5 classes similar to that of UserInformation and same settings in the File Properties window where they are just simple POCO and only have public auto propteries. These all seem to be coming through and I can access them and see them in the Object Browser. For some strange reason I cannot PathNames class to come through. I have tried to add some new dummy classes and have the same issue as PathNames class. Can someone tell me what I am doing wrong please.
The web service old ASMX
Web service client is being created through VS add service reference
Using VS 2017 pro - version 15.6.7.
After publish if I de-compile the dll then the PathNames class is there. So it's clearly in the dll.
I have look at this but still no luck.
Using Data Contracts in web service
Service can't expose private/read-only properties. DataMember attribute is used for marking public members or properties (with public getter and setter) of class marked with DataContract attribute. DataContract can be used as parameter or return value of operation.
Windows Communication Foundation (WCF) uses a serialization engine called the Data Contract Serializer by default to serialize and deserialize data (convert it to and from XML), and XML serialization (by default) doesn't serialize read=only properties.
For More Information you can read the MS Docs for Data Contracts :- https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts
To understand the various Limitation of Data Contracts please refer : -https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/types-supported-by-the-data-contract-serializer
Solution :
Anyway. What are you trying to do? Exposing properties means that you expect some stateful behavior. If you going to use this property in operation contract, which is seems to be, then you you must define the properties with public getter and setter so it can be serialized.
As the #Nikosi stated in previous answer, you have to define public setter for your BaseDirectoryPath property.
The only difference based on the example provided that one property is readonly while the other can be modified.
In order to make the class serializable consider rafactoring the property
public class PathNames {
private string _pathA = "Some Path";
private string _pathB = "Another Path";
public PathNames() {
BaseDirectoryPath = Path.Combine(_pathA, _pathB);
}
public string BaseDirectoryPath { get; set; }
}
You can use a default constructor to set the default value of the property
or just have an empty setter on the property
public class PathNames {
private string _pathA = "Some Path";
private string _pathB = "Another Path";
public string BaseDirectoryPath {
get {
return Path.Combine(_pathA, _pathB);
}
set {
//No OP
}
}
}
You can see how creating a Custom ASP.NET Web Service.
Might you need to rebuild web service ASP.Net and add your assembly to the global assembly cache (GAC).
I hope this help you.
I have created a client server application which is currently able to send messages as containers:
[Serializable]
public class MsgContainer
{
public string TableName { get; set; }
public bool SomethingBool { get; set; }
public DataTable DataTableData { get; set; }
}
The problem: Depending on the request from the user I would like the server to be able to send Forms
public Form requestedForm { get; set; }
The problem with that (as i have read in the web and tried in my application) WinForms are not serializable which is why i receive the following error:
System.Runtime.Serialization.SerializationException: 'Type 'System.Windows.Forms.Form' in Assembly 'System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' is not marked as serializable.'
Is there any workaround to my problem?
I would strongly advise you find a different approach to whatever you're trying to do. The Form is not serializable. You could:
Make a serializable class to transfer all the form information and regenerate a form based on it.
Write your own serializer and deserializer for a form.
Either way you would need to overcome the many following issues, such as:
Components in the form are also not serializable.
Each control may have a value or a binding to a data source that also needs to be transferred.
You can include infinite different objects and classes in a form that would be part of your main project. Everything would need to be in a library consumed by both server and client.
Basically, this would be your worst nightmare and after spending however much time you may spend working on it, you will eventually realise that you have nothing but bin filler.
You cannot (reasonably) serialise a form.
A better approach, if viable, would be to build the forms into the client app. Then have the server instruct the client as to which form to open. Optionally use an enum for this.
public enum FormType
{
Products,
Customers
}
public FormType RequestedForm { get; set; }
Sending a Form is a pretty pointless excersise. Forms are just there to Display data. If you want a certain form to be dispalyed, send the Data it needs rather then the whole Form.
Honestly it sounds like you either have some very faulty design. Or wanted to do a WebApplication the whole time. Consider that you might be stuck in a XY Problem.
I have an Asp.Net MVC 5.1 website. We've got 3 types of users and I want to add support for chat between one type of them. I have thought of some models like this:
public class Conversation
{
public NormalUser A { get; set; }
public NormalUser B { get; set; }
public List<PrivateMessaage> Messages { get; set; }
}
public class PrivateMessaage
{
public NormalUser Sender { get; set; }
public NormalUser Receiver { get; set; }
public string Message { get; set; }
public DateTime Created { get; set; }
}
Also, I'm using SignalR in other parts of the project and thought like it's a very good solution to add the chat interface on top of the SignalR. Everything looks good so far. However, I think hitting the database to insert a new message EVERY time a message is being typed is not a good idea. I've created so many strategies to implement custom donut caching in my website to make every single page as fast as possible and it seems like this would cancel all of them out! What is the preferred solution to this problem? I think I might take some approaches like these:
Push them to the database in batches. For instance once a message is past a threshold (its date/time difference is more than X or the message count is more than Y).
Don't support offline messages, just push them in-memory to the other side through SignalR.
Same as the 2nd, but support offline when the target user is offline. I imagine not many messages will be sent to offline users!
Don't cache anything. I'll work out!!
One issue with the first one is that, there might be a situation where the website would go down (for update, power failure, apocalypse(!), etc.) and all the messages in memory would be lost. I can add a custom action to flush everything but it's never quite safe. Since there's a lot of chat solutions out there, I think there are very convenient solutions to this.
If you are not opposed to using other databases, realtime chat is extremely easy using Firebase and AngularJS.
I need to write a RESTful WCF service that maintains a dictionary (or any other suitable data structure) with userId:userData as key:value pairs.
For that I first need to implement an interface for getting and setting userData (the specific configuration is enclosed):
GetConfiguration() : returns default config when user hasn’t set a config yet
GetConfiguration(string id)
SetConfiguration(string id, Configuration configurationSchema)
Then I'll need to write a service that implements this interface.
As a newbie in WCF I'm not sure how to do it. I tried to look for relevant references but didn't found any.
Appreciate any help/relevant references, Thanks !
The userData object:
public class ConfigurationSchema
{
public string MobileNumber { get; set; }
public List<string> Habits { get; set; }
public ConfigurationSchema(string mobileNumber, List<string> habits)
{
this.MobileNumber = mobileNumber;
this.Habits = habits;
}
}
may be below video will help you to create a WCF service. Once create simple WCF service after that add your code.
https://www.youtube.com/watch?v=GzN1vHWlJjA
If you did not find references to help you, I'd suggest you learn to google before you tackle programming problems. It's worth it. For your problem:
Open Visual Studio
Chose WCF project
Replace example complex data structure by your own class
Rename methods
Rename interface
Press F5