Can anyone advise of a good pattern for using a WCF Service from an ASP.net Page? It seems that if the lifetime of the Client(:ServiceModel.ClientBase) is not properly controlled that we get PipeException thrown. It currently exists as a field of the Page class, but is being reinstantiated upon each page request without being cleaned up (the .Close method).
I suspect this question could be rephrased "Managing limited resources in an ASP.net page", and is probably more related to the lifecycle of an ASP.net page. I'm new to ASP.net, so my understanding of this is a little thin.
TIA.
EDIT: Some code (there's not much to it!)
public partial class Default : Page
{
//The WCF client... obviously, instantiating it here is bad,
//but where to instantiate, and where to close?
private readonly SearchClient client = new SearchClient();
protected void Page_Load(object sender, EventArgs e)
{
2nd Edit: Would the following be better?
public partial class Default : Page
{
private SearchClient client;
protected void Page_Unload(object sender, EventArgs e)
{
try
{
client.Close();
}
catch
{
//gobbled
}
}
protected void Page_Load(object sender, EventArgs e)
{
client= new SearchClient();
//.....
I agree with Michael, abstract it out into another layer if possible.
However, if you are going to call it from your aspx page, I would just create a separate method to call it, return its results and cleanup. Keeps the code clean by having it all in one place. Just remember to dispose in your finally block, and that the wcf proxy will have to be cast to IDisposable in order to dispose.
for instance:
void Page_Load(object sender, EventArgs e)
{
if(!IsPostBack)
{
RemoteCall();
}
}
void RemoteCall()
{
var client = new SearchClient();
try
{
var results = client.Search(params);
clients.Close();
}
catch(CommunicationException cex)
{
//handle
}
catch(Exception ex)
{
//handle
}
finally
{
((IDisposable)client).Dispose();
}
}
In general, you shouldn't call external services directly from your presentation tier. It creates two problems: first, performance (pooling, scaling, etc), and second, it creates a security risk if you need to authenticate (authentication code in your DMZ is bad.
Even if you don't have an application tier, you should consider refactoring your service call to a private service in your presentation tier. This will allow you to decouple the service's lifecycle from the page's lifecycle (which is problematic as you have stated).
Related
In an ASP.Net project, using C#, I have a class (PlcComms.cs) for talking to a Controller (a PLC).
I want the one class object to be globally available, for each web page in my project.
I see from reading various forum posts that I should be able to create a public static object of my class type, i.e. PlcComms, in Global.asax.cs, or in a class in the App_Code folder. I've tried both and I write to the object ok, but when I go to read from it (from a timer in an update panel on the home web page) then it always read back as null.
I'm at a loss to know what to do at this point. can anyone help?
Currently, this is a class I have in the App_Code folder...
namespace SpearheadWeb
{
public static class AppGlobal
{
public static SpearheadWeb.PlcComms PlcCommsObject { get; set; }
}
}
this I have on my web page - it seems to create the object OK...
namespace SpearheadWeb
{
public partial class _Default : Page
{
private PlcComms CurrentPLC;
//some other here including ComPorts
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
try
{
//some settings reading and setup here
CurrentPLC = new PlcComms(Global.CommsSettings.CpuType1,Global.CommsSettings.Network1,ComPorts[0], Global.CommsSettings.IPAddress1, Global.CommsSettings.Path1,UpdatePanel.Controls[0].Controls, 1, Global.CommsSettings.MsUpdate1);
AppGlobal.PlcCommsObject = CurrentPLC;
but in my timer (the timer within an updatepanel) PLCComms1 is always null here...
protected void TimerUpdate_Tick(object sender, EventArgs e)
{
PlcComms PLCComms1 = AppGlobal.PlcCommsObject;
I have the following code:
public class BaseControlClass : System.Web.UI.UserControl
{
protected delegate void AsyncronousAction();
protected virtual void FAsyncEvent() { } //Overidden on derived classes.
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
FPerformAsyncronousTasks(FAsyncEvent);
}
protected virtual void FPerformAsyncronousTasks(AsyncronousAction AsyncCallback)
{
new Thread(delegate()
{
AsyncCallback();
}).Start();
}
}
public class DerivedControlClass : BaseClass
{
protected override void FAsyncEvent()
{
//Contact web service, wait for results, add to local database.
}
}
What I was expecting is for the page to load and the code in FAsyncEvent() in my derived class to run behind the scenes however, the page doesn't finish loading until the code in FAsyncEvent() has completed.
Am I doing something wrong with the threading here?
EDIT Strangely, I have noticed if I do a Clean -> Build then run the code, it works fine and the page finishes loading whilst the web service is being contacted. Subsequent runs though mean the page waits until the thread has finished processing.
Your code keeps the reference to the UserControl alive, which might be preventing the request from continuing. Try passing a static method to the new thread, just as a quick check and see if it helps.
I've only recently started to develop in ASP.NET, though I've been using C# for several years now. My first approach to ASP.NET was using MVC 4, but now I find myself working on a project that uses plain ASP.NET pages. I'm at a loss as to how the general framework works.
Specifically, I have no idea how to implement the Decorator Pattern in an ASP.NET page. I have a Product.aspx page and I have to add a feature to it. I thought that Decorator Pattern would be best based on the task requirements, and I immediately figured out how I would use it in MVC, since the actual logic that is executed lies in the Controller Action: there I would instantiate my decorator object.
But I have no idea how to do it in ASP.NET. As far as I can see, when the browser requests Product.aspx "something" creates an object of class Product (derived from Page), and then it's too late to decorate it.
Is it therefore possible to decorate a whole ASP.NET page (not just an object used by the code behind)? How would I do that?
I am not exactly sure what you wanna decorate, but;
You can create an HttpHandler that lets you do your work on a particular request as follows
public class MyHttpHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
if (context.Request.RawUrl.Contains("product.aspx"))
{
// may be you can execute your decorate business here
}
}
public bool IsReusable { get { return false; } }
}
Or may be you can use Global.asax 's OnBeginRequest event like as follows
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterOpenAuth();
RouteConfig.RegisterRoutes(RouteTable.Routes);
base.BeginRequest += OnBeginRequest;
}
private void OnBeginRequest(object sender, EventArgs e)
{
if (Request.RawUrl.Contains("product.aspx"))
{
//execute your business here..
}
}
First of all, according to your comment below the question, I can say that you should implement your showcase as a web user control (ascx)
You can decorate your ShowCase as follows,
public partial class ShowCase : System.Web.UI.UserControl, IShowCase
{
protected void Page_Load(object sender, EventArgs e){}
public void ApplyConfiguration(IConfiguration configuration)
{
throw new NotImplementedException();
}
}
public interface IShowCase
{
void ApplyConfiguration(IConfiguration configuration);
}
public abstract class Decorator : IShowCase
{
protected IShowCase ShowCase;
protected Decorator(IShowCase showcase)
{
ShowCase = showcase;
}
public virtual void ApplyConfiguration(IConfiguration configuration)
{
ShowCase.ApplyConfiguration(configuration);
}
}
public class ShowCaseDecoratorA : Decorator
{
public ShowCaseDecoratorA(IShowCase showcase) : base(showcase){ }
public override void ApplyConfiguration(IConfiguration configuration)
{
base.ApplyConfiguration(configuration);
//depending on the configuration, do something..
ShowCase.Visible = false;
}
}
public interface IConfiguration
{
//configuration
}
Then, from inside the page that uses ShowCase user control, you do something like this,
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
IConfiguration configuration = ConfigurationFactory.Get();
new ShowCaseDecoratorA(this.ShowCase).ApplyConfiguration(configuration);
}
}
I hope this gives you some inspiration..
I start building a new web service for my app and i want to make a global int for example that every time someone call this web service this int will increase in one.
this is what i create in visual studio:
public partial class Form : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
and i try to put static int in the class but it not work.
Put your variable in Application state.
Note you need to make it thread safe.
from http://msdn.microsoft.com/en-us/library/94xkskdf(VS.80).aspx
Application.Lock();
Application["PageRequestCount"] =
((int)Application["PageRequestCount"])+1;
Application.UnLock();
This issue is technology agnostic, but I am working with C# and ASP.NET and will use this for the pseudo code. Which is the better approach, and why?
Encapsulate logging, transaction and exception handling:
protected void Page_Load(object sender, EventArgs e) {
SomeBusinessClass.SomeBusinessMethod();
}
public class SomeBusinessClass {
public void SomeBusinessMethod() {
using (TransactionScope ts = new TransactionScope()) {
doStuff();
ts.Complete();
}
catch (Exception ex) {
LogError("An error occured while saving the order", ex);
}
}
}
}
Delegate logging, transaction and exception handling to the caller:
protected void Page_Load(object sender, EventArgs e) {
using (TransactionScope ts = new TransactionScope()) {
try {
SomeBusinessClass.SomeBusinessMethod();
ts.Complete();
}
catch (Exception ex) {
LogError("An error occured while saving the order", ex);
}
}
}
public class SomeBusinessClass {
public void SomeBusinessMethod() {
doStuff();
}
}
I am concerned that by introducing dependencies on logging, transactions, etc in my business logic code, I make it less generic. On the other hand, the UI code looks so much cleaner. I can't make the call. Let me know what other factors I should consider.
Transactions: a central concern of your business layer, so it should absolutely handle this (though you might centralize transaction handling via a unit of work implementation).
Update: I don't agree with this part any more. Often, the controller, presenter, or or another top-level caller is the best place to handle transactions (a la the the onion architecture) - in many cases, that's where the logical unit of work is defined.
Exception Handling: use as needed in every layer - but only use it in the business layer when you can actually do something about it (not just log it). Use a global handler in the UI layer if your infrastructure supports one.
Logging: use trace or informational logging in whatever layers need it, only log exceptions in the top layer.
Use Inversion of Control:
protected void Page_Load(object sender, EventArgs e) {
new SomeBusinessClass(_logger, _dbcontext, _exceptionhandler).SomeBusinessMethod();
}
A better one would be
protected void Page_Load(object sender, EventArgs e) {
_mybusinessclass.SomeBusinessMethod();
}
where _mybusiness class is passed to your page via IoC container, along with populated _logger, _dbcontext, and _exceptionhandler. If you need to create _exceptionhandler manually, for example "new RedirectExceptionHandler(this)", then
protected void Page_Load(object sender, EventArgs e) {
_mybusinessclass.SomeBusinessMethod(new RedirectExceptionHandler(this));
}
Now it really boils down to your specific design decisions. Don't know how to do IoC in ASP.NET, though, since I use MVC.
Another option is to use Aspect Oriented Programming to catch exceptions and do logging. Yet another option (available in www.sharparchitecture.net) is to handle transactions declaratively using [Transaction] attributes on method.
Anything that makes the UI thinner will make your life easier.