I am using reflection and WSDL to call web services on the fly through dynamically constructed proxy classes, and I have just added some overloaded web methods to one of the web services I am calling. Now I get an 'Ambigious match' error when trying to Invoke (via reflection) the method.
Here is the class that builds the service proxy and has a method to invoke any given web method in that proxy by name:
public class ServiceProxy
{
public ServiceMetadata Metadata { get; private set; }
public RemoteServiceElement Element { get; private set; }
public string IpAddress { get; private set; }
private object serviceProxy;
private string serviceAsmx;
public ServiceProxy(RemoteServiceElement element)
{
IpAddress = element.IpAddress;
Element = element;
serviceAsmx = "http://" + element.IpAddress + ":" + element.Port + "xxxx.asmx"
Build(serviceAsmx, "xxxx");
}
public ServiceProxy(string ip, string _asmx, string _serviceName)
{
IpAddress = ip;
serviceAsmx = _asmx;
Build(_asmx, _serviceName);
}
private void Build(string webServiceAsmx, string serviceName)
{
WebClient client = new WebClient();
Metadata = ServiceMetadata.OpenWsdl(webServiceAsmx);
Stream stream = client.OpenRead(webServiceAsmx + "?wsdl");
ServiceDescription description = ServiceDescription.Read(stream);
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
importer.ProtocolName = "Soap12";
importer.AddServiceDescription(description, null, null);
importer.Style = ServiceDescriptionImportStyle.Client;
importer.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;
CodeNamespace nmspace = new CodeNamespace();
CodeCompileUnit unit1 = new CodeCompileUnit();
unit1.Namespaces.Add(nmspace);
ServiceDescriptionImportWarnings warning = importer.Import(nmspace, unit1);
if (warning == 0)
{
CodeDomProvider provider1 = CodeDomProvider.CreateProvider("CSharp");
string[] assemblyReferences = new string[5] { "System.dll", "System.Web.Services.dll", "System.Web.dll",
"System.Xml.dll","System.Data.dll" };
CompilerParameters param = new CompilerParameters(assemblyReferences);
CompilerResults results = provider1.CompileAssemblyFromDom(param, unit1);
if (results.Errors.Count > 0)
{
foreach (CompilerError err in results.Errors)
{
Logger.Write("Compiler error assembling " + webServiceAsmx + " - " + err.ErrorText);
}
throw new Exception("Compiler error occurred calling the web service. Check log for details.");
}
serviceProxy = results.CompiledAssembly.CreateInstance(serviceName);
Logger.Write("Proxy service at + " + serviceAsmx + " assembled successfully");
}
}
public object Invoke(string methodName, object[] args = null)
{
MethodInfo info = serviceProxy.GetType().GetMethod(methodName);
object asmxResults = default(object);
try
{
asmxResults = info.Invoke(serviceProxy, args);
Logger.Write("Remote proxy at " + serviceAsmx + " - " + methodName + " - " + "invoked successfully");
}
catch (Exception e)
{
Logger.Write("Error invoking proxy class at " + serviceAsmx + " - " + e.InnerException);
}
return asmxResults;
}
}
This worked fine before I added any overloads. So I am guessing that using reflection + overloads may be causing an issue.
Here is a mock-up example of one of the WebMethods that causes the problem:
[WebMethod (MessageName="GetFoos")]
public List<Foo> GetFoos(DateTime dt)
{
// performs linq query
}
[WebMethod (MessageName = "GetFoosDynamic")]
public List<Foo> GetFoos(Expression exp)
{
// linq query
}
Same method name, different parameters + different 'MessageName' which is supposed to work for web services.
Thanks for any help.
SOAP doesn't support method overloading, but it looks like you've overridden your method name with the WebMethod attribute, so you should be calling the names you've defined within that attribute when you make your SOAP call.
Related
I have used json code to call the controller/action method and convert the json format inside the project,everything worked in my localhost and my server which i had, but it was not working in some other server like US server, I don't know why it throws.
Is it cause Network or IIS confirguration or code issue? If Firewall or port issue means how to change their settings?
I have attached the code which I tried,
Class :
public class Jsonget
{
public static string jsonconvert(string url)
{
string currentsite = HttpContext.Current.Request.Url.Authority;
WebClient wc = new WebClient();
wc.Encoding = Encoding.UTF8;
wc.Encoding = UTF8Encoding.UTF8;
var uri = new Uri(HttpContext.Current.Request.Url.AbsoluteUri);
var requestType = uri.Scheme;
string jsonurl = requestType + "://" + currentsite + url;
var jsondata = wc.DownloadString(jsonurl);
string jsonresult = "{\"results\":" + jsondata.ToString() + "}";
return jsonresult;
}
}
Index.cshtml:
jsonurl = Url.Action("GetallPrograms", "Admin", new { Name = "testprogram" });
getjsonresult = Jsonget.jsonconvert(jsonurl);
Newtonsoft.Json.Linq.JObject programList = Newtonsoft.Json.Linq.JObject.Parse(getjsonresult);
foreach (var pgm in programList["results"])
{
<p>#((string)pgm["ProgramName"])</p>
}
AdminController:
public JsonResult GetallPrograms(string Name)
{
var programList = new List<CustomAttribute>();
BaseController bc = new BaseController();
try
{
var Exist_programs = (from n in bc.db.Programs where n.Name == Name select n).ToList();
foreach (var exist in Exist_programs)
{
programList.Add(new CustomAttribute
{
ProgramName = exist.ProgramName,
Id = exist.Id.ToString()
});
}
}
catch
{
programList.Add(new CustomAttribute
{
ProgramName ="",
Id = ""
});
}
return Json(programList, JsonRequestBehavior.AllowGet);
}
Please give suggestion to fix this?
OK this is what I have. I have my main form frmMain.cs and I have a class.cs. I was doing an RSSFeed for my email and I get the error:
inaccessible due to its protective level.
On my class.cs I have the following code:
public class RSSFeed
{
public void CheckForEmails()
{
string GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
XmlUrlResolver xmlResolver = new XmlUrlResolver();
xmlResolver.Credentials = new NetworkCredential(Settings.Default.GmailUser, Settings.Default.GmailPassword);
XmlTextReader xmlReader = new XmlTextReader(GmailAtomUrl);
xmlReader.XmlResolver = xmlResolver;
try
{
XNamespace ns = XNamespace.Get("http://purl.org/atom/ns#");
XDocument xmlFeed = XDocument.Load(xmlReader);
var emailItems = from item in xmlFeed.Descendants(ns + "entry")
select new
{
Author = item.Element(ns + "author").Element(ns + "name").Value,
Title = item.Element(ns + "title").Value,
Link = item.Element(ns + "link").Attribute("href").Value,
Summary = item.Element(ns + "summary").Value
};
frmMain.MsgList.Clear();
frmMain.MsgLink.Clear();
foreach (var item in emailItems)
{
if (item.Title == String.Empty)
{
frmMain.MsgList.Add("Message from " + item.Author + ", There is no subject and the summary reads, " + item.Summary);
frmMain.MsgLink.Add(item.Link);
}
else
{
frmMain.MsgList.Add("Message from " + item.Author + ", The subject is " + item.Title + " and the summary reads, " + item.Summary);
frmMain.MsgLink.Add(item.Link);
}
}
if (emailItems.Count() > 0)
{
if (emailItems.Count() == 1)
{
frmMain.lblEmail.Text = ("You have one new email, would you like me to read it to you");
}
else
{
frmMain.lblEmail.Text("You have " + emailItems.Count() + "new emails");
}
}
else if (frmMain.QEvent == "CheckForNewEmails" && emailItems.Count() == 0)
{
frmMain.lblEmail.Text("You have no new emails"); frmMain.QEvent = String.Empty;
}
}
catch
{
frmMain.lblEmail.Text("You have submitted invalid log in information");
}
}
}
And then I have on my main form a timer tick event:
public void tmrEmail_Tick(object sender, EventArgs e)
{
lblEmail.Text = ("New Emails " + RSSFeed.CheckForEmails);
}
What I am not understanding is when I have the label in my RSSFeed or on my main form timer tick. I get the error. I have changed everything to public and it still is throwing the error.
Am I missing something or do I not have everything I should have?
Also I am going to have another form that is just dedicated to email. Would it be better to do away with the RSSFeed.cs and just code the winform? The only thing this is doing is creating a label when I have new emails.
Any thoughts?
You are missing the static keyword from your class and method. Should be public static class RSSFeed and public static void CheckForEmails()
You need to pass an instance of the frmMain to the method too. E.g.:
public static void CheckForEmails(frmMain frmMainInstance)
Putting it all together:
public static class RSSFeed
{
public static void CheckForEmails(frmMain frmMainInstance)
{
string GmailAtomUrl = "https://mail.google.com/mail/feed/atom";
XmlUrlResolver xmlResolver = new XmlUrlResolver();
// ... rest of your code ...
}
}
And the call to it would be something like:
public void tmrEmail_Tick(object sender, EventArgs e)
{
// The following line will produce a compile error because
// CheckForEmails doesn't return a value
// lblEmail.Text = ("New Emails " + RSSFeed.CheckForEmails(this);
// Try this instead:
RSSFeed.CheckForEmails(this);
}
Note that I am assuming tmrEmail_Tick is a method in frmMain, hence I am passing this as the argument to CheckForEmails.
Instead of making RSSFeed and CheckForEmails static you could instantiate an instance of RSSFeed:
public void tmrEmail_Tick(object sender, EventArgs e)
{
RSSFeed feed = new RSSFeed();
feed.CheckForEmails(this);
}
Note that you still need to pass frmMain instance as an argument to CheckForEmails.
My website is using facebook as it's oauth provider. Users will be able to buy things through my site so I want to force them to authenticate even if they already have an active session with facebook.
I found this link in facebook's api documentation that discusses reauthentication but I can't get it to work with my mvc app. Anyone know if this is possible?
var extra = new Dictionary<string, object>();
extra.Add("auth_type", "reauthenticate");
OAuthWebSecurity.RegisterFacebookClient(
appId: "**********",
appSecret: "**********************",
displayName: "",
extraData: extra);
Found the solution. I had to create my own client instead of using the default one provided by OAuthWebSecurity.RegisterFacebookClient
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Helpers;
namespace Namespace.Helpers
{
public class MyFacebookClient : DotNetOpenAuth.AspNet.Clients.OAuth2Client
{
private const string AuthorizationEP = "https://www.facebook.com/dialog/oauth";
private const string TokenEP = "https://graph.facebook.com/oauth/access_token";
private readonly string _appId;
private readonly string _appSecret;
public MyFacebookClient(string appId, string appSecret)
: base("facebook")
{
this._appId = appId;
this._appSecret = appSecret;
}
protected override Uri GetServiceLoginUrl(Uri returnUrl)
{
return new Uri(
AuthorizationEP
+ "?client_id=" + this._appId
+ "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
+ "&scope=email,user_about_me"
+ "&display=page"
+ "&auth_type=reauthenticate"
);
}
protected override IDictionary<string, string> GetUserData(string accessToken)
{
WebClient client = new WebClient();
string content = client.DownloadString(
"https://graph.facebook.com/me?access_token=" + accessToken
);
dynamic data = Json.Decode(content);
return new Dictionary<string, string> {
{
"id",
data.id
},
{
"name",
data.name
},
{
"photo",
"https://graph.facebook.com/" + data.id + "/picture"
},
{
"email",
data.email
}
};
}
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
{
WebClient client = new WebClient();
string content = client.DownloadString(
TokenEP
+ "?client_id=" + this._appId
+ "&client_secret=" + this._appSecret
+ "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
+ "&code=" + authorizationCode
);
NameValueCollection nameValueCollection = HttpUtility.ParseQueryString(content);
if (nameValueCollection != null)
{
string result = nameValueCollection["access_token"];
return result;
}
return null;
}
}
}
and then in AuthConfig.cs...
OAuthWebSecurity.RegisterClient(
new MyFacebookClient(
appId: "xxxxxxxxxx",
appSecret: "xxxxxxxxxxxxxxxx"),
"facebook", null
);
As a note to those that happen upon this if your Facebook Authentication stopped working when v2.3 became the lowest version you have access to (non versioned calls get the lowest version an app has access to). The API now returns JSON and not name value pairs so you have to update the QueryAccessToken method shown above by #Ben Tidman
Below is the updated method
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
{
WebClient client = new WebClient();
string content = client.DownloadString(
TokenEP
+ "?client_id=" + this._appId
+ "&client_secret=" + this._appSecret
+ "&redirect_uri=" + HttpUtility.UrlEncode(returnUrl.ToString())
+ "&code=" + authorizationCode
);
dynamic json = System.Web.Helpers.Json.Decode(content);
if (json != null)
{
string result = json.access_token;
return result;
}
return null;
}
There's one issue in using the MyFacebookClient implementation.
Probably someone tryin to implement it came across the error:
The given key was not present in the dictionary
attempting to call the ExternalLoginCallback method in ActionController.
The error raises when the method
OAuthWebSecurity.VerifyAuthentication(Url.Action("ExternalLoginCallback", new { ReturnUrl = returnUrl }));
is called.
In order to get it working the method VerifyAuthentication has to be overridden.
In particular the
public virtual AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl);
overload of the abstract class OAuth2Client.
If you use the following:
public override AuthenticationResult VerifyAuthentication(HttpContextBase context, Uri returnPageUrl)
{
string code = context.Request.QueryString["code"];
string rawUrl = context.Request.Url.OriginalString;
//From this we need to remove code portion
rawUrl = Regex.Replace(rawUrl, "&code=[^&]*", "");
IDictionary<string, string> userData = GetUserData(QueryAccessToken(returnPageUrl, code));
if (userData == null)
return new AuthenticationResult(false, ProviderName, null, null, null);
AuthenticationResult result = new AuthenticationResult(true, ProviderName, userData["id"], userData["name"], userData);
userData.Remove("id");
userData.Remove("name");
return result;
}
}
finally you get the method called in the right way and no excpetion is thrown.
I call a a methode by HttpPost in my ServiceController from my View http://localhost/Case/Form
My serviceController class:
using System.Web;
using System.Web.Mvc;
[...]
namespace ApnNephro.WebUI.Controllers
{
public class ServicesController : Controller
{
public string GetDomain()
{
string url = "";
try
{
string _url = Request.Url.AbsolutePath;
int _si = (_url.IndexOf("//"));
int _fi = (_url.Substring(_si + 2)).IndexOf("/"); // first /
url = _url.Substring(0, _fi + _si + 2);
return url.ToString();
}
catch (InvalidOperationException ioe)
{
throw new Exception(ioe.Message + " / " + ioe.StackTrace);
}
catch (Exception e)
{
throw new Exception(e.Message + " / " + e.StackTrace);
}
return url.ToString();
}
[...]
And i call him in my MailHelper.cs :
private static string domain = new ServicesController().GetDomain();
But an exception occure because Request is null...
So, my Question is, why Request is null ?
Is it assigned only in the current view controller, so here in my CaseController only ?
You are creating a new controller, that is not associated with a request.
Instead of putting the get domain in a controller and then creating a new one,
You can just access the current request via the HttpContext.Current.Request.
This is also available in a static method.
I'm trying to get the following to work on my machine but I get an error (Cannot create an instance of the abstract class or interface 'System.ServiceModel.Channels.MessageHeader')
using System;
using System.IO;
using System.Reflection;
namespace com.companyname.business
{
/// <summary>
/// Summary description for SessionCreateRQClient.
/// </summary>
class SessionCreateRQClient
{
/// <summary>
/// The main entry point.
/// </summary>
[STAThread]
static void Main(string[] args)
{
try
{
// Set user information, including security credentials and the IPCC.
string username = "user";
string password = "password";
string ipcc = "IPCC";
string domain = "DEFAULT";
string temp = Environment.GetEnvironmentVariable("tmp"); // Get temp directory
string PropsFileName = temp + "/session.properties"; // Define dir and file name
DateTime dt = DateTime.UtcNow;
string tstamp = dt.ToString("s") + "Z";
//Create the message header and provide the conversation ID.
MessageHeader msgHeader = new MessageHeader();
msgHeader.ConversationId = "TestSession"; // Set the ConversationId
From from = new From();
PartyId fromPartyId = new PartyId();
PartyId[] fromPartyIdArr = new PartyId[1];
fromPartyId.Value = "WebServiceClient";
fromPartyIdArr[0] = fromPartyId;
from.PartyId = fromPartyIdArr;
msgHeader.From = from;
To to = new To();
PartyId toPartyId = new PartyId();
PartyId[] toPartyIdArr = new PartyId[1];
toPartyId.Value = "WebServiceSupplier";
toPartyIdArr[0] = toPartyId;
to.PartyId = toPartyIdArr;
msgHeader.To = to;
//Add the value for eb:CPAId, which is the IPCC.
//Add the value for the action code of this Web service, SessionCreateRQ.
msgHeader.CPAId = ipcc;
msgHeader.Action = "SessionCreateRQ";
Service service = new Service();
service.Value = "SessionCreate";
msgHeader.Service = service;
MessageData msgData = new MessageData();
msgData.MessageId = "mid:20001209-133003-2333#clientofsabre.com1";
msgData.Timestamp = tstamp;
msgHeader.MessageData = msgData;
Security security = new Security();
SecurityUsernameToken securityUserToken = new SecurityUsernameToken();
securityUserToken.Username = username;
securityUserToken.Password = password;
securityUserToken.Organization = ipcc;
securityUserToken.Domain = domain;
security.UsernameToken = securityUserToken;
SessionCreateRQ req = new SessionCreateRQ();
SessionCreateRQPOS pos = new SessionCreateRQPOS();
SessionCreateRQPOSSource source = new SessionCreateRQPOSSource();
source.PseudoCityCode = ipcc;
pos.Source = source;
req.POS = pos;
SessionCreateRQService serviceObj = new SessionCreateRQService();
serviceObj.MessageHeaderValue = msgHeader;
serviceObj.SecurityValue = security;
SessionCreateRS resp = serviceObj.SessionCreateRQ(req); // Send the request
if (resp.Errors != null && resp.Errors.Error != null)
{
Console.WriteLine("Error : " + resp.Errors.Error.ErrorInfo.Message);
}
else
{
msgHeader = serviceObj.MessageHeaderValue;
security = serviceObj.SecurityValue;
Console.WriteLine("**********************************************");
Console.WriteLine("Response of SessionCreateRQ service");
Console.WriteLine("BinarySecurityToken returned : " + security.BinarySecurityToken);
Console.WriteLine("**********************************************");
string ConvIdLine = "convid="+msgHeader.ConversationId; // ConversationId to a string
string TokenLine = "securitytoken="+security.BinarySecurityToken; // BinarySecurityToken to a string
string ipccLine = "ipcc="+ipcc; // IPCC to a string
File.Delete(PropsFileName); // Clean up
TextWriter tw = new StreamWriter(PropsFileName); // Create & open the file
tw.WriteLine(DateTime.Now); // Write the date for reference
tw.WriteLine(TokenLine); // Write the BinarySecurityToken
tw.WriteLine(ConvIdLine); // Write the ConversationId
tw.WriteLine(ipccLine); // Write the IPCC
tw.Close();
//Console.Read();
}
}
catch(Exception e)
{
Console.WriteLine("Exception Message : " + e.Message );
Console.WriteLine("Exception Stack Trace : " + e.StackTrace);
Console.Read();
}
}
}
}
I have added the reference System.ServiceModel and the lines:
using System.ServiceModel;
using System.ServiceModel.Channels;
but I continue to get that error when trying to compile --
Cannot create an instance of the abstract class or interface 'System.ServiceModel.Channels.MessageHeader'
I am using Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM
Microsoft .NET Framework
Version 3.5 SP1
Professional Edition
Is there another reference I have to add? Or a dll to move over?
I wonder was the code above written for Framework 2.0 only?
Thanks for your help.
The error message is correct, you cannot create an instance of that class, it is declared abstract.
http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.messageheader.aspx
See if the static method MessageHeader.CreateHeader will work for you. Note there is several overloads, so pick the best one for you.