I have a class with this structure
class A
{
List Blist;
}
Class B
{
int i;
}
I need my AIF web service operation to accept a single object A that may have multiple instances of B in it. I get an error when i try to deploy the service.
Do i need to explicitly specify AifCollectionTypeAttribute for B in the operation method even though B is contained in A?
You have to use AifCollectionTypeAttribute('return') and type.
Example:
[
DataMemberAttribute('AttributeValues'),
AifCollectionTypeAttribute('return', Types::Class, classStr(AttributeValueDC)),
AifCollectionTypeAttribute('attributeValues', Types::Class, classStr(AttributeValueDC))
]
public List parmAttributeValues(List _attributeValues = attributeValues)
{
attributeValues = _attributeValues;
return attributeValues;
}
Related
Web services cannot return an anonymous type.
If you are building a LINQ query using classes through a datacontext... you cannot construct instances of those classes in a query.
Why would I want to do this? Say I want to join three "tables" or sets of objects. I have three items with a foreign key to each other. And say the lowest, most detailed of these was represented by a class that had fields from the other two to represent the data from those. In my LINQ query I would want to return a list of the lowest, most detailed class. This is one way I have decided to "join some tables together" and return data from each of them via LINQ to SQL via a WebService. This may be bad practice. I certainly do not like adding the additional properties to the lowest level class.
Consider something like this... (please ignore the naming conventions, they are driven by internal consideration) also for some reason I need to instantiate an anonymous type for the join... I don't know why that is... if I do not do it this way I get an error...
from su in _dataContext.GetTable<StateUpdate>()
join sfs in _dataContext.GetTable<SystemFacetState>()
on new { su.lngSystemFacetState } equals new { lngSystemFacetState = sfs.lngSystemFacetState }
join sf in _dataContext.GetTable<SystemFacet>()
on new { sfs.lngSystemFacet } equals new { lngSystemFacet = sf.lngSystemFacet }
join s in _dataContext.GetTable<System>()
on new { sf.lngSystem } equals new {lngSystem = s.lngSystem}
select new
{
lngStateUpdate = su.lngStateUpdate,
strSystemFacet = sf.strSystemFacet,
strSystemFacetState = sfs.strSystemFacetState,
dtmStateUpdate = su.dtmStateUpdate,
dtmEndTime = su.dtmEndTime,
lngDuration = su.lngDuration,
strSystem = s.strSystem
}
).ToList();
Notice I have to build the anonymous type which is composed of pieces of each type. Then I have to do something like this... (convert it to a known type for transport via the web service)
result = new List<StateUpdate>(from a in qr select(new StateUpdate
{
lngStateUpdate = a.lngStateUpdate,
strSystemFacet = a.strSystemFacet,
strSystemFacetState = a.strSystemFacetState,
dtmStateUpdate = a.dtmStateUpdate,
dtmEndTime = a.dtmEndTime,
lngDuration = a.lngDuration,
strSystem = a.strSystem
}));
It is just awful. And perhaps I have created an awful mess. If I am way way off track here please guide me to the light. I feel I am missing something fundamental here when I am adding all these "unmapped" properties to the StateUpdate class.
I hope someone can see what I am doing here so I can get a better way to do it.
You can create a 'dto' class which just contains the properties you need to return and populate it instead of the anonymous object:
public class Result
{
public string lngStateUpdate
{
get;
set;
}
... // other properties
}
then use it like this:
from su in _dataContext.GetTable<StateUpdate>()
...
select new Result
{
lngStateUpdate = su.lngStateUpdate,
... // other properties
}
Nitpick note - please ditch the Hungarian notation and camel casing for properties :)
I think the answer is to create another object to serve as a DTO. This object would not be mapped to the data context and can contain fields that cross the mapped objects. This solves the problems of repetitive properties in the mapped objects, and allows for instantiation of the DTO class in the query as it is not mapped.
FYI: with respect to the problem with the join- I revisited that and I think I may have had the inner and outer components of the join switched around before.
Imagine a simple controller action IEnumerable<BaseType> Get(). It returns an enumeration of different types all deriving from BaseType.
When the client requests XML, the result is something like this:
<ArrayOfBaseType>
<BaseType i:type="DerivedType1"><A>value</A></BaseType>
<BaseType i:type="DerivedType2"><B>value</B></BaseType>
<BaseType i:type="DerivedType3"><C>value</C></BaseType>
</ArrayOfBaseType>
As you can see, the type of the derived class is transmitted in the i:type attribute.
If the client requests JSON however, this information is missing:
[
{"A":"value"},
{"B":"value"},
{"C":"value"}
]
How to fix this?
The following change is necessary:
In the WebApiConfig.cs the following line needs to be added:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling =
TypeNameHandling.Auto;
This will automatically result in a new property $type when needed.
If you write your class following:
public class MyClass
{
// properties here
public string IType
{
get
{
return this.GetType().Name;
}
set { }
}
}
Maybe, it will help you
Possibly not specific to webservices, but...
I have a webmethod that returns:
List<Tadpole> myList = getList();
return new { data = myList , count = 5 };
It returns this as JSON.
my code checks myList[x].fishsticks which isn't actually part of the Tadpole class (so it errors). I am wondering, can I add a fishsticks attribute to myList somehow to avoid the error, so it gets included when I return the data?
Is there perhaps another elegant solution for doing this?
In your example, you'll have to add a fishsticks property to Tadpole.
public class Tadpole
{
//....
public int Fishsticks { get; set; }
}
Also, why are you adding a .Count property to your JSON type? Wouldn't it make more sense to just .data.Count, or just return the list and skip the wrapper entirely?
I haven't checked what properties of List<> get serialized lately, so it's possible that it's not included, but even if that's the case it would make more sense to do this:
List<Tadpole> myList = getList();
return new { data = myList , count = myList.Count };
Or, create a descendant class that overrides .Count and adds a serialization attribute.
Edit
If I remember correctly, anonymous/dynamic types are internally implemented as dictionaries, while classes are, well, not. (BTW, anonymous types and dynamic objects bring a host of performance and maintenance issues along with them.)
If you don't want to modify Tadpole for some reason, you could always create a descendant class:
public class HungryTadpole : TadPole
{
public int FishSticks { get; set; }
}
Strong typing is your friend and will save you many headaches down the road.
We are developing a CRM application. All the business logic and data access go through WCF services. We have 2 options for communication between WCF and client (at the moment: ASP.NET MVC 2)
One option is create method for each operations. Example
GetCustomers()
GetCustomersWithPaging(int take, int skip)
GetCustomersWithFilter(string filter)
GetCustomersWithFilterPaging(string filter, int take, int skip)
or // new .net 4 feature
GetCustomers(string filter = null, int take = 0, int skip = 0)
... list goes..
Another option is create a generic single service operation called
Response InvokeMessage(Messege request). Example
wcfservice.InvokeMessage(
new CustomerRequest {
Filter = "google",
Paging = new Page { take = 20, skip = 5}
});
// Service Implementation.
public Response InvokeMessage(Message request)
{
return request.InvokeMessage();
}
InvokeMessage = generic single service call for all operation.
CustomerRequest = Inherited class from Message abstract class, so I can create multiple classes from Message base class depend on the input requirements.
Here is the CustomerRequest class.
public class CustomerRequest : Message
{
public string Filter {get;set;}
public Page Paging {get;set} // Paging class not shown here.
Public override Response InvokeMessage()
{
// business logic and data access
}
}
EDIT
public abstract class Message
{
public abstract Response InvokeMessage();
}
// all service call will be through InvokeMessage method only, but with different message requests.
Basically I could avoid each service call's and proxy close etc..
One immediate implication with this approach is I cannot use this service as REST
What is the recommended approach if the service needs to call lots of methods?
thanks.
If you use the facade pattern you can have both.
First, build your services using the first option. This allows you to have a REST interface. This can be used externally if required.
You can then create a facade that uses Invoke message style, this translates the request based on the parameters and calls one of the individual services created in the first step.
As to the question of multiple specific operations vs one general query - either approach could be valid; defining fine-grained vs coarse-grained operations is to some degree a matter of taste.
When faced with a similar requirement in our RESTful service, I've chosen to create a filter class that reads parameters from the query-string, available thusly:
public NameValueCollection ReadQuerystring()
{
return WebOperationContext.Current.IncomingRequest.UriTemplateMatch.QueryParameters;
}
The larger issue that I see here is that you're subclassing Message for your operation parameters - is there a reason why you're doing that? The best practice is to create data contracts (objects annotated with [DataContract] attributes) for such a purpose.
My scenario:
This is an ASP.NET 4.0 web app programmed via C#
I implement a repository pattern. My repositorys all share the same ObjectContext, which is stored in httpContext.Items. Each repository creates a new ObjectSet of type E. Heres some code from my repository:
public class Repository<E> : IRepository<E>, IDisposable
where E : class
{
private DataModelContainer _context = ContextHelper<DataModelContainer>.GetCurrentContext();
private IObjectSet<E> _objectSet;
private IObjectSet<E> objectSet
{
get
{
if (_objectSet == null)
{
_objectSet = this._context.CreateObjectSet<E>();
}
return _objectSet;
}
}
public IQueryable<E> GetQuery()
{
return objectSet;
}
Lets say I have 2 repositorys, 1 for states and 1 for countrys and want to create a linq query against both. Note that I use POCO classes with the entity framework. State and Country are 2 of these POCO classes.
Repository stateRepo = new Repository<State>();
Repository countryRepo = new Repository<Country>();
IEnumerable<State> states = (from s in _stateRepo.GetQuery()
join c in _countryRepo.GetQuery() on s.countryID equals c.countryID
select s).ToList();
Debug.WriteLine(states.First().Country.country)
essentially, I want to retrieve the state and the related country entity. The query only returns the state data... and I get a null argument exception on the Debug.WriteLine
LazyLoading is disabled in my .edmx... thats the way I want it.
You're doing a join without retrieving anything from it. There are multiple solutions to your problem:
Use Include to load the dependent entities: from s in ((ObjectSet<State>) _stateRepo.GetQuery).Include("Country"). The problem with this approach is that you should expose the ObjectSet directly rather than as a IQueryable if you want to avoid casting.
Use context.LoadProperty(states.First(), s => s.Country) to explicitly load the Country from the database for a given state.
Select both entities in the query: from s in ... join c ... select new { s, c }. You won't be able to access directly the state's Country property but you have it in the anonymous type.
Enable lazy loading.
Your repository implementation is very similar to mine, especially the way you are storing the ObjectContext. It works fine for me, so I don't think it's a conceptual problem.
Try using a static objectcontext (no wrapper) just to see if that fixes the problem. Perhaps there is a bug in your ContextHelper which causes your context to get disposed and recreated.