ASMX schema varies when using WCF Service - asmx

I have a client (created using ASMX "Add Web Reference"). The service is WCF. The signature of the methods varies for the client and the Service. I get some unwanted parameteres to the method.
Note: I have used IsRequired = true for DataMember.
Service: [OperationContract]
int GetInt();
Client: proxy.GetInt(out requiredResult, out resultBool);
Could you please help me to make the schame non-varying in both WCF clinet and non-WCF client? Do we have any best practices for that?
using System.ServiceModel;
using System.Runtime.Serialization;
namespace SimpleLibraryService
{
[ServiceContract(Namespace = "http://Lijo.Samples")]
public interface IElementaryService
{
[OperationContract]
int GetInt();
[OperationContract]
int SecondTestInt();
}
public class NameDecorator : IElementaryService
{
[DataMember(IsRequired=true)]
int resultIntVal = 1;
int firstVal = 1;
public int GetInt()
{
return firstVal;
}
public int SecondTestInt()
{
return resultIntVal;
}
}
}
Binding = "basicHttpBinding"
using NonWCFClient.WebServiceTEST;
namespace NonWCFClient
{
class Program
{
static void Main(string[] args)
{
NonWCFClient.WebServiceTEST.NameDecorator proxy = new NameDecorator();
int requiredResult =0;
bool resultBool = false;
proxy.GetInt(out requiredResult, out resultBool);
Console.WriteLine("GetInt___"+requiredResult.ToString() +"__" + resultBool.ToString());
int secondResult =0;
bool secondBool = false;
proxy.SecondTestInt(out secondResult, out secondBool);
Console.WriteLine("SecondTestInt___" + secondResult.ToString() + "__" + secondBool.ToString());
Console.ReadLine();
}
}
}
Please help..
Thanks
Lijo

I don't think you can do much to make this "non-varying" - that's just the way the ASMX client side stuff gets generated from the WCF service. Each client-side stack is a bit different from the other, and might interpret the service contract in the WSDL in a slightly different manner. Not much you can do about that.....
If you don't want this - create a WCF client instead.
A remark on the side:
public class NameDecorator : IElementaryService
{
[DataMember(IsRequired=true)]
int resultIntVal = 1;
This is very strange how you're trying to put a DataMember (a field that should be serialized across for the service) into the class that implements the service.....
You should keep your service contract (interface IElementaryService), service implementation (class NameDecorator) and your data contracts (other classes) separate - do not mix data contract and service implementation - this is sure to backfire somehow....

Related

how can i reduce memory usage on my application running on azure

I am learning how to use the .NET framework. I am working with ASP .NET core. I have never had or hit my azure webhosting quota until recently I keep hitting quota by making very few request and this started ever since I installed dotnetbrowser library. its the best library for my project because it makes getting data easier. however, I will appreciate if someone can tell me how to get same data without using a browser control like web browser or dotnetbrowser. the data I needed go through multiple server and client communications before the needed value is provided. So my question is how can achieve the same thing without using browser control?
finally, my code might be buggy given that I am not too familiar with threads and task. I might be using too much memory. so below is my code
using DotNetBrowser;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Web.Http;
namespace AjaxRequest.Controllers
{
public class ValuesController : ApiController
{
private static ManualResetEvent waitEvent;
private static List<string> ajaxUrls = new List<string>();
static string str = "";
public static Browser browser;
public ValuesController()
{
waitEvent = new ManualResetEvent(false);
browser = BrowserFactory.Create();
browser.Context.NetworkService.ResourceHandler = new AjaxResourceHandler();
browser.Context.NetworkService.NetworkDelegate = new AjaxNetworkDelegate();
}
// GET api/values
public string Get(int id, string title)
{
string Title = title.Replace(" ", "-");
browser.LoadURL(string.Format("https://ba.com/foo/{0}-{1}/something.html", Title, id));
waitEvent.WaitOne();
browser.Dispose();
string Json = Regex.Replace(str, #"\\","");
return Json.Replace("\\\"", "\"");
}
public class AjaxResourceHandler : ResourceHandler
{
//HomeController hc;
public bool CanLoadResource(ResourceParams parameters)
{
if (parameters.ResourceType == ResourceType.XHR && parameters.URL.Contains("https://something.com/ajax/blahblah"))
{
ajaxUrls.Add(parameters.URL);
}
return true;
}
}
public class AjaxNetworkDelegate : DefaultNetworkDelegate
{
//HomeController hc;
public override void OnDataReceived(DataReceivedParams parameters)
{
if (ajaxUrls.Contains(parameters.Url))
{
PrintResponseData(parameters.Data);
}
}
public void PrintResponseData(byte[] data)
{
str = Encoding.UTF8.GetString(data);
ajaxUrls.Clear();
browser.Stop();
browser.dispose();
waitEvent.Set();
}
public void error(string info)
{
str = info;
waitEvent.Set();
}
}
}
}
is it possible that I am doing it wrong? if that's the case how can it be improved to conserve memory or data?
UPDATE: am using azure free hosting services
DotNetBrowser is a Chromium wrapper - I am not entirely sure why you would need it in a web app, but that said, it is likely it is the culprit. Once you remove it, you can use HttpClient to perform the right requests with no memory overhead.
Profiling-wise, your best bet is to start with Application Insights - it's enabled by default in ASP.NET Core projects. It will allow resource tracking across app components.
It seems like you have more than one running Browser instance.
I can suggest to check that Browser instance is disposed correctly. If not, you can try to dispose it in the Dispose method of the controller.

Event and error logging in Asp.net MVC 5 project

I am looking at implementing a logging mechanism in a site of mine, I wish to do basic user action logging. I don't want to log every single button they click on, but I do want to log actions they do which makes changes.
Are there any libraries or articles / tutorials out there which can help me implement a good and efficient logging mechanism for my asp.net site. Im not sure if there are any changes in MVC5 that might come in use for logging as I know user Authentication and Authorization has changed a fair amount from 4 to 5.
I'm sure that there is a dynamic library out there that will work in many different situations.
Nice to haves:
Async capability
Scalable
Simple to use
I'm thinking along the lines of creating a custom filter or attribute that then logs the suers action, but that's just my Idea, Im here to ask what the standard / industry way to do it is.
There isn't an industry standard.
I've used filters or I've overridden the "onActionExecuting" method on the base controller class to record controller / action events.
EDIT ::
Trying to be more helpful but this is really vague.
If you're worried about errors and things like that use elmah.
For other logging use Nlog or Log4Net.
If you're trying to do extra logging like auditing or something like that you can use any combination of those, or something custom. In my site I created a table that stores every click on the site by creating an object sort of like this :
public class audit
{
public int ID { get; set; }
public DateTime AuditDate { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public Dictionary<string, object> values
}
In my base constructor, I overrode the OnActionExecuting event :
protected override void OnActionExecuting(ActionExecutingContext ctx)
{
checkForLogging(ctx);
//do not omit this line
base.OnActionExecuting(ctx);
}
Lets say I want to log all Get Requests using my new audit object
private void checkForLogging(ActionExecutingContext ctx)
{
//we leave logging of posts up to the actual methods because they're more complex...
if (ctx.HttpContext.Request.RequestType == "GET")
{
logging(ctx.ActionDescriptor.ActionName, ctx.ActionDescriptor.ControllerDescriptor.ControllerName, ctx.ActionParameters);
}
}
Thats all the info I need to fill my logging object with the action name, the controller name and all the params passed into the method. You can either save this to a db, or a logfile or whatever you want really.
The point is just its a pretty big thing. This is just one way to do it and it may or may not help you. Maybe define a bit more what exactly you want to log and when you want to do it?
You can create a custom attribute and decorate methods with it and then check if that attribute is present when the OnActionExecuting method fires. You can then get that filter if present and read from it and use that to drive your logging if you want...
Maybe this example will help.
My focus on logging is in the CREATE, EDIT, DELETE actions.
I am using MVC 5 Code-first EF 6.1 (VS 2013) ,
and for this example I are referring to the Create action for an entity called "WorkFlow"
I actually view these logs from SSRS, but you could add a controller and Views for WriteUsageLog and view them from the MVC application
MODEL: Create a MODEL Entity called "WriteUsageLog" which will be where the log records are kept
CONTROLLER: Extract, or refactor, the HttpPost overload of the "Create" action from the WorkFlowController into a Partial Class called "WorkFlowController" (These partials are to avoid being deleted and rebuilt when I use the wizard to create Controllers)
Other Classes in the CONTROLLER folder: Then there are some helper functions that are required in a class called "General_Object_Extensions" and "General_ActiveDirectory_Extensions" (NOTE: these are not really 'extensions')
Add the following line to the DBContext:
public DbSet WriteUsageLogs { get; set; }
The advantage of this example is:
I am recording the following for the record:
User Name from Active Directory
The DateTime that the log record is being created
The computer name
And a Note that consists of the values for all the entity properties
I am recording the log in a table from which I can access it either using an MVC controller, or preferably from SQL Server Report Server. Where I can monitor all my MVC applications
/Models/WriteUsageLog.cs
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MileageReimbursement.Models
{
public class WriteUsageLog
{
public WriteUsageLog()
{
this.DateTimeCreated = DateTime.Now; // auto-populates DateTimeCreated field
}
[Key]
public int WriteUsageLogID { get; set; }
[Column(TypeName = "nvarchar(max)")]
public string Note { get; set; }
public string UserLogIn { get; set; }
public string ComputerName { get; set; }
public DateTime DateTimeCreated { get; private set; } //private set to for auto-populates DateTimeCreated field
}
}
/Controllers/ControllerPartials.cs
using System.Linq;
using System.Web.Mvc;
using MileageReimbursement.Models;
//These partials are to avoid be deleted and rebuilt when I use the wizard to create Controllers
namespace MileageReimbursement.Controllers
{
public partial class WorkFlowController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "whatever")] WorkFlow workFlow)
{
...
if (ModelState.IsValid)
{
db.WorkFlows.Add(workFlow);
db.SaveChanges();
//===================================================================================================================
string sX = workFlow.GetStringWith_RecordProperties();
//===================================================================================================================
var logRecord = new WriteUsageLog();
logRecord.Note = "New WorkFlow Record Added - " + sX;
logRecord.UserLogIn = General_ActiveDirectory_Extensions.fn_sUser();
string IP = Request.UserHostName;
logRecord.ComputerName = General_functions.fn_ComputerName(IP);
db.WriteUsageLogs.Add(logRecord);
db.SaveChanges();
//===================================================================================================================
return RedirectToAction("Index");
}
else // OR the user is directed back to the validation error messages and given an opportunity to correct them
{
...
return View(workFlow); //This sends the user back to the CREATE view to deal with their errors
}
}
}
}
/Controllers/ControllerExtensions.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Web;
namespace MileageReimbursement.Controllers
{
public static class General_ActiveDirectory_Extensions
{
public static string fn_sUser()
{
char cX = '\\';
string sUser = General_functions.fn_ReturnPortionOfStringAfterLastOccuranceOfACharacter(HttpContext.Current.User.Identity.Name, cX);
return sUser; //returns just the short logon name Example for 'accessiicarewnc\ggarson', it returns 'ggarson'
}
} //General_ActiveDirectory_Extensions
public static class General_Object_Extensions
{
public static string GetStringWith_RecordProperties(this object Record)
{
string sX = null;
Dictionary<string, object> _record = GetDictionary_WithPropertiesForOneRecord(Record);
int iPropertyCounter = 0;
foreach (var KeyValuePair in _record)
{
iPropertyCounter += 1;
object thePropertyValue = _record[KeyValuePair.Key];
if (thePropertyValue != null)
{
sX = sX + iPropertyCounter + ") Property: {" + KeyValuePair.Key + "} = [" + thePropertyValue + "] \r\n";
}
else
{
sX = sX + iPropertyCounter + ") Property: {" + KeyValuePair.Key + "} = [{NULL}] \r\n";
}
}
return sX;
}
public static Dictionary<string, object> GetDictionary_WithPropertiesForOneRecord(object atype)
{
if (atype == null) return new Dictionary<string, object>();
Type t = atype.GetType();
PropertyInfo[] props = t.GetProperties();
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach (PropertyInfo prp in props)
{
object value = prp.GetValue(atype, new object[] { });
dict.Add(prp.Name, value);
}
return dict;
}
} //General_Object_Extensions
public static class General_functions
{
public static string fn_ComputerName(string IP)
{
//USAGE
//From: http://stackoverflow.com/questions/1444592/determine-clients-computer-name
//string IP = Request.UserHostName;
//string compName = CompNameHelper.DetermineCompName(IP);
IPAddress myIP = IPAddress.Parse(IP);
IPHostEntry GetIPHost = Dns.GetHostEntry(myIP);
List<string> compName = GetIPHost.HostName.ToString().Split('.').ToList();
return compName.First();
}
static public string fn_ReturnPortionOfStringAfterLastOccuranceOfACharacter(string strInput, char cBreakCharacter)
{
// NOTE: for path backslash "/", set cBreakCharacter = '\\'
string strX = null;
//1] how long is the string
int iStrLenth = strInput.Length;
//2] How far from the end does the last occurance of the character occur
int iLenthFromTheLeftOfTheLastOccurance = strInput.LastIndexOf(cBreakCharacter);
int iLenthFromTheRightToUse = 0;
iLenthFromTheRightToUse = iStrLenth - iLenthFromTheLeftOfTheLastOccurance;
//3] Get the Portion of the string, that occurs after the last occurance of the character
strX = fn_ReturnLastXLettersOfString(iLenthFromTheRightToUse, strInput);
return strX;
}
static private string fn_ReturnLastXLettersOfString(int iNoOfCharToReturn, string strIn)
{
int iLenth = 0;
string strX = null;
int iNoOfCharacters = iNoOfCharToReturn;
iLenth = strIn.Length;
if (iLenth >= iNoOfCharacters)
{
strX = strIn.Substring(iLenth - iNoOfCharacters + 1);
}
else
{
strX = strIn;
}
return strX;
}
} //General_functions
}
I would agree that Log4Net and NLog seem to be the two most commonly used products on the different projects I have been a member.
If you are looking for a great tool that you can use for logging, error handling and anything else where AOP would be beneficial I would highly recommend PostSharp (http://www.postsharp.net/). You set your logging/error handling up centrally and then just decorate methods. It is a well documented and supported product. They have a community license, which is free - and it is free for individuals. They also have professional and ultimate versions of the products, which would make more sense if you're using it as a team.
I don't work at PostSharp :-) I've just used it in the past and really like it.

Testing Methods with Reference to Web.Config in .Net C#

I searched a lot and still couldn't find a solid solution for this. Suppose you have methods in your application. This methods use "System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration" to access some setting in the web.config. If you try to test these methods, your tests will fail because your test project doesn't have web.config.
What is the best way to solve this problem. For projects with simple config file, I usually use a method like this as facade method.
public class Config
{
public static String getKeyValue(String keyName)
{
if (keyName == String.Empty) return String.Empty;
String result = "";
System.Configuration.Configuration rootWebConfig1 =
System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(null);
if (rootWebConfig1.AppSettings.Settings.Count > 0)
{
System.Configuration.KeyValueConfigurationElement reportEngineKey =
rootWebConfig1.AppSettings.Settings[keyName];
if (reportEngineKey != null)
{
result = reportEngineKey.Value;
}
}
return result;
}
}
Every time I tried to set the path for OpenWebConfiguration( ), I got the error "The relative virtual path is not allowed"
To make that scenario more testable, I usually take the approach of making a "settings manager" of my own, and giving it an interface. So for example:
public interface IConfig
{
string GetSettingValue(string settingName);
}
Then I can have my "real" implementation:
public sealed class Config : IConfig
{
public string GetSettingValue(string settingName)
{
// your code from your getKeyValue() method would go here
}
}
Then my code that uses it would take in an instance of this (this is an example of the Dependency Inversion Principal):
public void DoStuff(IConfig configuration)
{
string someSetting = configuration.GetSettingValue("ThatThingINeed");
// use setting...
}
So now for my production code, I can call DoStuff and pass in an instance of Config.
When I need to test, I can use a mocking tool (Moq, JustMock, RhinoMocks, etc) to create a fake IConfig that returns a known value without hitting the actual .config file, or you can do it without a mocking framework by making your own mocks (and store them in your test project).
public class ConfigMock : IConfig
{
private Dictionary<string, string> settings;
public void SetSettingValue(string settingName, string value)
{
settings[settingName] = value;
}
public string GetSettingValue(string settingName)
{
return settings[settingName];
}
}
and
[Test]
public void SomeExampleTest()
{
var config = new ConfigMock();
config.SetSettingValue("MySetting", "SomeValue");
var underTest = new MyClass();
underTest.DoStuff(config);
}
The easiest way to do this is to use a mocking library such as moq. It takes a bit of time to figure it out, but once you do you can abstract away most of your plumbing to return the values you need for repeatable, consistent testing.

Instancing in WCF - Query specific to Mode.PerSession

I am using Instancing mode as PerSession - If a client makes multiple request for a given method - o/p should be incremented as per below code snippet b/c Instancing mode is
PerSession,
However I am always getting value as 1 for every call, ideally it should be incremented.
Let me know what I am missing
Thanks in advance...
Server
[ServiceContract]
public interface IServer
{
[OperationContract]
int GetData();
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
public class Service1 : IServer
{
int count = 0;
public int GetData()
{
count++;
return count;
}
}
Client
ServiceReference1.IServer obj = new ServiceReference1.ServerClient();
Console.WriteLine(obj.GetData());
Console.WriteLine(obj.GetData());
what is the binding you have ? basicHttpBinding does not support PerSession instance mode it defaults to PerCall.
If you have basicHttpBinding change that to wsHttpBinding and try.

Is this supposed to work this way?

I have this code up on my server here (Yes I known ASMX is a bad idea but WCF doesn't work at all for some reason):
<%# WebService Language="C#" Class="Test" %>
using System.Web;
using System.Web.Services;
[WebService(Namespace = "http://smplsite.com/smplAccess")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Test : System.Web.Services.WebService
{
State s;
public Test()
{
s = (Session["foo"] ?? (Session["foo"] = new State())) as State ;
}
[WebMethod(EnableSession = true)]
public void Set(int j) { i=j; }
[WebMethod(EnableSession = true)]
public int Get() { return i; }
}
class State
{
public int i = 5;
}
when I run the folloing code:
class Program
{
static void Main(string[] args)
{
var ser = new ServiceReference1.TestSoapClient();
Console.WriteLine(ser.Get());
ser.Set(3);
Console.WriteLine(ser.Get());
}
}
I expect to get back:
5
3
but I got back
5
5
My Solution
Usee wsdl.exe to generate a proxy class
Add references as needed to get it to compile
Use Martin's solution
This Seems related
Edit: Added State object.
Web services are stateless, so they do not store their state between multiple calls. Everytime you call a method, a new instance of the service will be created and its members will have the default values again.
What you can do, is to enable session state (as you have done) and store your state in the ASP.NET session.
Something like this:
[WebMethod(EnableSession = true)]
public void Set(int j) { Session["i"] = j; }
[WebMethod(EnableSession = true)]
public int Get() { return Session["i"] == null ? 5 : (int)Session["i"]; }
This was what is required on the server side. But you also have to take care on the client side:
Since an ASP.NET session is identified by a cookie, you have to make sure that you are passing the same cookie to the server with every web method call. To do so, you have to instantiate a CookieContainer and assign it to the web service proxy instance:
static void Main(string[] args)
{
var ser = new ServiceReference1.TestSoapClient();
ser.CookieContainer = new System.Net.CookieContainer();
// ...
}
You need to turn on sessions.
[WebMethod(EnableSession = true)]
It looks to me like its not persisting class state between session method calls - probably a new object is being called each time. I'm actually not sure that you can rely on getting the same object instance each time you call the service. Joshua's answer is correct, but you'll also need to write code to persist your service's internal field into that session.

Resources