I'm using VisualStudio2013. Its important to note for readers that the code which this asmx is derived from works perfectly but I do not know how to use the asmx WebService. I downloaded the whole nine yards from here https://sourceforge.net/projects/shorturl-dotnet/
I cannot figure out how to get/set properties of the following CreateUrl() WebMethod. I want to learn how to use the entire WebService but started here.
In the example that follows I send a URL to the CreateURL() method which will shorten the URL and perform other tasks; I do not know how to get properties from the returned ShortUrl.Container Class: I have not been successful accessing the data after the class(es) are returned to my calling method.
// WebMethod
public class API : System.Web.Services.WebService {
[WebMethod]
public ShortUrl.Container CreateUrl(string real_url)
{
ShortUrl.Container oShortUrl = new ShortUrl.Container();
oShortUrl.RealUrl = real_url;
oShortUrl.ShortenedUrl = ShortUrl.Utils.UniqueShortUrl();
oShortUrl.CreateDate = DateTime.Now;
oShortUrl.CreatedBy = HttpContext.Current.Request.UserHostAddress;
ShortUrl.Utils.AddUrlToDatabase(oShortUrl);
oShortUrl.ShortenedUrl = ShortUrl.Utils.PublicShortUrl(oShortUrl.ShortenedUrl);
return oShortUrl;
}
}
// ShortUrl.Container class returned as oShortUrl
namespace ShortUrl
{
/// <summary>
/// Container for the ShortURL object
/// </summary>
public class Container
{
private string _real_url;
private string _short_url;
private DateTime _create_date;
private string _created_by;
public Container()
{
this.CreateDate = DateTime.Now;
this.CreatedBy = "tap";
this.RealUrl = null;
this.ShortenedUrl = "Unknown";
}
public string RealUrl
{
get { return _real_url; }
set { _real_url = value; }
}
public string ShortenedUrl
{
get { return _short_url; }
set { _short_url = value; }
}
public DateTime CreateDate
{
get { return _create_date; }
set { _create_date = value; }
}
public string CreatedBy
{
get { return _created_by; }
set { _created_by = value; }
}
}
}
In VS2013 I add the Service Reference to point to http://tap.tools.api.asmx as the service endpoint and name the VS2013 reference as ShortenUrl. VS2013 generates the APISoapClient and Container classes.
// get/set properties of the ShortUrl.Container class
// by means of APISoapClient
ShortenUrl.APISoapClient u = new ShortenUrl.APISoapClient();
u.CreateUrl("http://clintongallagher.com/tag-target-url.html");
// get/set properties of the ShortUrl.Container class
// by means of Container class
ShortenUrl.Container c = new ShortenUrl.Container();
string url = c.RealUrl;
I'm not getting anywhere with either and I think my problem is the instance of the oShortUrl object instantiated within the public ShortUrl.Container CreateUrl(string real_url) method. I do not know how to get any of the properties from that instance of oShortUrl the Container class returns to my methods.
// oShortUrl
ShortUrl.Container oShortUrl = new ShortUrl.Container();
Odd as it may sound as old and outdated the use of asmx happens to be I never worked with -any- WebServices yet which explains why I am weak and throw myself to the mercy of the court.
// EDIT: 2016-07-19 ~2:41pm
VS2013 generated several classes from the WSDL two of which appear to be useful as seen in Intellisense...
// class APISoapClient and class Container
When I use a local variable with APISoapClient a shortened URL is generated as I can see using SQL Management Studio and note all of the data is properly generated but I am not able to get/set on any other WebMethods or properties with to get/set data...
// Exposes two WebMethods: CreateUrl and GetUrl
ShortenUrl.APISoapClient u = new ShortenUrl.APISoapClient();
// Does generate the shortened URL
u.CreateUrl("http://clintongallagher.com/tag-target-url.html");
// Should return the URL that was shortened but doesn't
u.GetUrl("i2Z5H");
And...
// Exposes the properties in Intellisense but does not return data
ShortenUrl.Container c = new ShortenUrl.Container();
// returns 1/1/0001 12:00:00 AM
lblCreateDate.Text = "CreateDate: " + c.CreateDate.ToString();
// returns nothing
lblCreatedBy.Text = "CreatedBy: " + c.CreatedBy;
// returns nothing
lblRealUrl.Text = "RealUrl: " + c.RealUrl;
// returns ShortenUrl.Container
lblShortenedUrl.Text = "ShortenedUrl: " + u.GetUrl("i2Z5H");
If i understood what you're trying to get is the Container returned from the Web Method. If so then just create a variable type of Container and assign the method call to it. Like ShortUrl.Container c = u.CreateUrl(...) then from c you can get the values you're looking for.
Think about this #clintongallagher. When you do the following call,
ShortenUrl.APISoapClient u = new ShortenUrl.APISoapClient();
u.CreateUrl("http://clintongallagher.com/tag-target-url.html");
[WebMethod]
public ShortUrl.Container CreateUrl(string real_url)
{
ShortUrl.Container oShortUrl = new ShortUrl.Container();
oShortUrl.RealUrl = real_url;
//here you're assigning a value to this object, let's say 'A'
oShortUrl.ShortenedUrl = ShortUrl.Utils.UniqueShortUrl();
oShortUrl.CreateDate = DateTime.Now;
oShortUrl.CreatedBy = HttpContext.Current.Request.UserHostAddress;
//then here you're saving the object with the Shortened value 'A' you just got
ShortUrl.Utils.AddUrlToDatabase(oShortUrl);
/*
*finally you're replacing the Shortened value with another value,
*let's say 'B', which is the object you're going to return*/
oShortUrl.ShortenedUrl = ShortUrl.Utils.PublicShortUrl(oShortUrl.ShortenedUrl);
return oShortUrl;
}
I don't know how does GetUrl(shortened_value) is supposed to work but, assuming it will get from the DB the shortened_value passed in, of course the result would not be the same since the shortened value saved was 'A' and your asking for B.
Related
I have a project which is about RESTful API and I have as a property the basic URL, on which I need to add parts each time (that's in my methods). I need (a) to declare the default (unchanged) path, and then (b) some help on how do I add to the URL. Example:
public partial class APIParamaters
{
public System.Uri URL { get; set; } = (System.Uri) "http://192.100.106.657:8811/some/part/here/version1/api"; //throws error !!!
}
This is throwing an error and I don't know how to correct.
Also, how do I later add to the URL, for example, I am trying
class MyTest
{
public string SpecialPart = "Excellent";
public APIParamaters myParams = new APIParamaters
{
URL = URL + SpecialPart + "FirstCall", //trying to do: "http://192.100.106.657:8811/some/part/here/version1/api/Excellent/FirstCall"
SomethingElse = "Ok"
//etc..
};
}
The following code means (cast this string as System.Uri) but string can not be cast as System.Uri:
(System.Uri) "http://192.100.106.657:8811/some/part/here/version1/api";
You should instantiate System.Uri:
public System.Uri URL { get; set; } = new System.Uri("http://192.100.106.657:8811/some/part/here/version1/api");
How to render null string properties as empty strings in ASP.NET MVC4 Web API v.1 in json result?
WebAPI renders them as
"myproperty": null
how to render this as
"myproperty": ""
controller is
public class Customer {
public string myproperty { get; set; }
}
public class CustomersController : ApiController
{
public HttpResponseMessage Get()
{
var cust = new Customer();
return Request.CreateResponse(HttpStatusCode.OK,
new { customers = cust.ToArray() });
}
}
object are nested and contain lot of string properties. Setting them all to empty strings in constructor seems ugly. API caller needs empty strings or 0 for decimals, it does not like null constant in any value.
you can decorate your properties like this :
[JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)]
[DefaultValue("")]
public string myproperty{ get; set; }
Note that you can set the default value handling to populate in a global config like this:
GlobalConfiguration
.Configuration
.Formatters
.JsonFormatter
.SerializerSettings
.DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.Populate;
So, you don't need to decorate it to every property. You will only need to use the DefaultValue.
public class Customer {
private string _myproperty = String.Empty;
public string myproperty
{
get { return _myproperty; };
set { _myproperty = value ?? String.Empty; }
}
}
i give little overhead but solve my problem
DataTable dt = (new tst()).Gettable();
string s = string.Empty;
s = Newtonsoft.Json.JsonConvert.SerializeObject(dt);
s= s.Replace("null", "\"\"");
Object obj = Newtonsoft.Json.JsonConvert.DeserializeObject(s);
return Ok(obj);
As default web api works like this...
you don't need to change
I am designing an API wrapper in C# for Asana, a project management solution. During the design process, I ran into a few roadblocks. I am wondering what a good way to design the API wrapper would be.
The Asana API I am integrating with works with REST. The requests return JSON.
There will be 6 data classes (User, Task, Project, etc), each containing a bunch of strings to hold the data returned from the REST requests. My first idea with these classes is to give them each factory Parse() constructors so I can easily pass in json and get a data object in return. I realize I can't extract the static factory methods into an interface.
I will have a REST request class that will manage sending and receiving data from the REST server. It will always return a JSON string.
Finally, I would like a AsanaAPI class that will contain methods to wrap those exposed on the REST server (i.e GetUser, GetAllUsers, GetTask). Every method either returns a specific data class or an array of data classes. Here are the two cases:
public User GetSingleUser(string userID = "me")
{
if(userID == "") throw new ArgumentException("UserID cannot be blank");
string url = string.Format("{0}/{1}{2}", userUrl, userID, "?opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name");
JSONNode root = JSON.Parse(GetResponse(url))["data"];
return User.Parse(root);
}
public List<User> GetAllUsers()
{
List<User> users = new List<User>();
string url = string.Format("{0}{1}", userUrl, "?opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name");
JSONArray root = JSON.Parse(GetResponse(url))["data"].AsArray;
foreach(JSONNode userRoot in root)
{
users.Add(User.Parse(userRoot));
}
return users;
}
Each method will have that same format, but the User type will be replaced with Project, Task, etc. I want to extract the logic in these two methods because there will be many more methods with almost the exact same format.
In summary, the roadblocks I ran into were the fact that
I can't extract the factory constructor method from the data class.
I can't extract the parsing logic from the request methods
Is there something I can do with generics or is there just a better way of designing this project?
So I created a Parsable interface containing only a Parse method. Each data type implements Parsable. I was able to extract the parsing logic using generic types. It isn't the prettiest solution, but it does work.
public User GetSingleUser(string userID = "me")
{
if(userID == "") throw new ArgumentException("UserID cannot be blank");
string url = "{baseUrl}/users/{userID}?{opt_fields}".FormatWith(
new { baseUrl = BASE_URL, userID = userID, opt_fields = "opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name" });
return (User)ParseJson<User>(AsanaRequest.GetResponse(url));
}
public User[] GetAllUsers()
{
string url = "{baseUrl}/users?{opt_fields}".FormatWith(
new { baseUrl = BASE_URL, opt_fields = "opt_fields=id,name,email,workspaces,workspaces.id,workspaces.name" });
return (User[])ParseJsonArray<User>(AsanaRequest.GetResponse(url));
}
public T ParseJson<T>(string json) where T : Parsable, new()
{
JSONNode root = JSON.Parse(json)["data"];
T ret = new T();
ret.Parse(root);
return ret;
}
public T[] ParseJsonArray<T>(string json) where T : Parsable, new()
{
JSONArray root = JSON.Parse(json)["data"].AsArray;
T[] nodes = new T[root.Count];
for(int i = 0; i < root.Count; i++)
{
T newParsable = new T();
newParsable.Parse(root[i]);
nodes[i] = newParsable;
}
return nodes;
}
Ok, I've got this singleton-like web class which uses session to maintain state. I initially thought I was going to have to manipulate the session variables on each "set" so that the new values were updated in the session. However I tried using it as-is, and somehow, it remembers state.
For example, if run this code on one page:
UserContext.Current.User.FirstName = "Micah";
And run this code in a different browser tab, FirstName is displayed correctly:
Response.Write(UserContext.Current.User.FirstName);
Can someone tell me (prove) how this data is getting persisted in the session? Here is the class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class UserContext
{
private UserContext() { }
public static UserContext Current
{
get
{
if (System.Web.HttpContext.Current.Session["UserContext"] == null)
{
UserContext uc = new UserContext();
uc.User = new User();
System.Web.HttpContext.Current.Session["UserContext"] = uc;
}
return (UserContext)System.Web.HttpContext.Current.Session["UserContext"];
}
}
private string HospitalField;
public string Hospital
{
get { return HospitalField; }
set
{
HospitalField = value;
ContractField = null;
ModelType = null;
}
}
private string ContractField;
public string Contract
{
get { return ContractField; }
set
{
ContractField = value;
ModelType = string.Empty;
}
}
private string ModelTypeField;
public string ModelType
{
get { return ModelTypeField; }
set { ModelTypeField = value; }
}
private User UserField;
public User User
{
get { return UserField; }
set { UserField = value; }
}
public void DoSomething()
{
}
}
public class User
{
public int UserId { get; set; }
public string FirstName { get; set; }
}
I added this to a watch, and can see that the session variable is definitely being set somewhere:
(UserContext)System.Web.HttpContext.Current.Session["UserContext"];
As soon as a setter is called the Session var is immediately updated:
set
{
HospitalField = value; //<--- here
ContractField = null;
ModelType = null;
}
The UserContextinstance is saved in Session with this line:
System.Web.HttpContext.Current.Session["UserContext"] = uc;
It's not a singleton. The static property UserContext will attempt to retrieve a instance from Session, and if it doesn't find it, create a new instance and store it in Session.
UPDATE
I can see how the session var is retrieved, my confusion is around how the session var is set.
To add clarification following Micah's comment: the first time the static Current property is accessed, a new UserContext instance is created, its User property is populated with a new User instance, and the UserContext instance is stored in Session. Subsequent accesses to UserContext.Current (and hence UserContext.Current.User) in the same session are all accessing the same instance.
If it's still not clear I suggest stepping through with a debugger.
public static UserContext Current
{
get
{
// If Session does not yet contain a UserContext instance ...
if (System.Web.HttpContext.Current.Session["UserContext"] == null)
{
// ... then create and initialize a new UserContext instance ...
UserContext uc = new UserContext();
uc.User = new User();
// ... and store it in Session where it will be available for
// subsequent requests during the same session.
System.Web.HttpContext.Current.Session["UserContext"] = uc;
}
// By the time we get here, Session contains a UserContext instance,
// so return it.
return (UserContext)System.Web.HttpContext.Current.Session["UserContext"];
}
}
Joe is right. Your usage is: UserContext.Current.User.FirstName
In the getter of UserContext.Current, you're getting back a reference to a piece of memory that lives inside the session object within asp.net. Using any of the setters should/would change that memory and if you inspect the session object either in the debugger or on subsequent lines of code, you should see the same data that you set with your setters.
And run this code in a different
browser tab, FirstName is displayed
correctly:
You are saving it in the session. Opening a new tab can use the same session information as the other tab (I'm not certain about all browsers). Try opening a new browser window (not just a tab), and see what happens.
I'm trying to test code around a web service that is not available yet. I'm trying to dummy up my own version. According to the specs it will be called like this.
var service = new Service();
service.SD = new ServiceData();
service.SD.ID = "ABC123";
service.SD.Auth = "00000";
string result = service.DoMyThing();
This is the closest I've gotten.
var service = new Service();
service.set_SD(new ServiceData());
service.get_SD().ID = "ABC123";
service.get_SD().Auth = "00000";
service.DoMyThing();
The problem is with the SD property. How do I write the service so that Visual Studio 2008 generates the web reference correctly?
Here is my current dummy web service code.
public class Service : System.Web.Services.WebService
{
// This doesn't show up in the generated proxy at all
public static ServiceData SDTest;
// For extra credit explain why this needs to be static for it to work
private static ServiceData _sd;
public ServiceData SD
{
[WebMethod(EnableSession = true)]
get { return _sd; }
[WebMethod(EnableSession = true)]
set { _sd = value; }
}
[WebMethod]
public string DoMyThing()
{
// Presumably the real service accesses SD in here
return "";
}
}
public class ServiceData
{
public string ID { get; set; }
public string Auth { get; set; }
}
Your design is flawed. Web services are not meant to have properties. They should only expose methods, the reason being that the HTTP protocol is stateless (and web services assume this too), so exposing a property doesn't make sense unless you want it to apply to all callers of the instance (and still, even in that situation, it doesn't make sense to expose it).
Rather, what you want to do is have the DoMyThing method take the instance of ServiceData (if required) and operate on that, returning the appropriate result set.
If you really have a need to expose properties of the service, you would have a GetProperties method (or something like that) which takes no parameters and returns the appropriate data structure with the service information.
I'm with casperOne on this. I think using fakie properties are more annoying than useful.
Still, if you're married to this just eliminate the getter for the property. You don't need it. Do this instead:
var service = new Service();
ServiceData sd = new ServiceData();
sd.ID = "ABC123";
sd.Auth = "00000";
service.SD = sd;
string result = service.DoMyThing();
If Visual Studio still names the setter property incorrectly you can use one of the soap attributes to rename it.
EDIT: You'll also need to define SD as a SOAP Header.
You can't do this, so don't try to "fake it". The best you can do is:
var service = new Service();
ServiceData sd = new ServiceData();
sd.ID = "ABC123";
sd.Auth = "00000";
string result = service.DoMyThing(sd);
For those that may be interested.
This more accurately reflects the spec than my sanitized version above (I didn't know "TypeNameValue" was a key clue, sorry!).
var service = new Service();
service.ServiceDetailsValue = new ServiceDetails();
service.ServiceDetailsValue.ID = "ABC123";
service.ServiceDetailsValue.Auth = "00000";
string result = service.DoMyThing();
And this is the dummy web service code that works.
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(Name="TestService", ConformsTo = WsiProfiles.BasicProfile1_1)]
public class Service : System.Web.Services.WebService
{
public ServiceDetails SDTest;
[WebMethod]
[SoapDocumentMethod(Binding = "TestService")]
[SoapHeader("SDTest", Required = true)]
public string DoMyThing()
{
return "";
}
}
public class ServiceDetails : System.Web.Services.Protocols.SoapHeader
{
public string ID { get; set; }
public string Auth { get; set; }
}