how to use built-in content type negotiation and just get access to the decision - asp.net-mvc-4

I wanted to take advantage of built-in content negotiator and just get access to decision what formatter is going to be used. I don't want to use Request.Headers.Accept and check for whether it is json or xml content type because there lot of things are involved in that decision. Is there a way I can check at controller level or override any class that tells me what formatter going to be used OR what request content type is?
thanks in advance.

You can run conneg manually:
var conneg = Configuration.Services.GetContentNegotiator();
var connegResult = conneg.Negotiate(
typeof(YOUR_TYPE), Request, Configuration.Formatters
);
And use the output whichever way you want:
//the valid media type
var mediaType = connegResult.MediaType;
//do stuff
//the relevant formatter
var formatter = connegResult.Formatter;
//do stuff

If you want to see what is going on then install a TraceWriter and you will see what the conneg does.
A TraceWriter looks something like:
public class TraceWriter : ITraceWriter {
public bool IsEnabled(string category, TraceLevel level) {
return true;
}
public void Trace(HttpRequestMessage request, string category, TraceLevel level, Action<TraceRecord> traceAction) {
var rec = new TraceRecord(request, category, level);
traceAction(rec);
Log(rec);
}
private void Log(TraceRecord record) {
Console.WriteLine(record.Message);
}
}
and is installed like this,
config.Services.Replace(typeof(ITraceWriter), new TraceWriter());
If you want to manually invoke conneg then you can use,
config.Services.GetContentNegotiator().Negotiate(...)

Tugberk has a blog on this. Have a look.

Related

InputFormatter for Single Request

Is there a way to include an InputFormatter which only runs for a single endpoint?
We have 1 solitary endpoint which has a need for a custom InputFormatter.
So we don't really want to add an input formatter globally, for the benefit of a single endpoint. I don't really want to write a hacky middleware which would run for every request either. Some kind of ActionFilter would have been perfect.
I've seen existing SO answers on this very topic, but they all have answers which require an outdated API e.g. the InputFormatters collection is no longer available on the context in Action Filters.
Cheers
Here is an example which helps you to control the input formatter for an action method.
public class CSPContentTypeFormatterAttribute : ResultFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext context)
{
var options = context
.HttpContext
.RequestServices
.GetService(serviceType: typeof(IOptions<MvcOptions>)) as IOptions<MvcOptions>;
var mvcOptions = options.Value;
mvcOptions.InputFormatters.OfType<SystemTextJsonInputFormatter>().First()
.SupportedMediaTypes.Add(
new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/csp-report")
);
base.OnResultExecuting(context);
}
}

Alternate Model Binding On Controllers Post Action

EDIT: You can safely clone https://github.com/vslzl/68737969 and run the example. If you send
{
"intPropB":3
}
as POST body to: http://localhost:5000/api/Test
you'll see it binds clearly B object to A object.
#EDIT END
I'd like to implement alternate model binding using asp.net core 5 As you will see below, I have two alternative classes to bind at a single endpoint. Each request can contains only a valid A model or B model and A and B has different properties.
[HttpPost(Name = Add)]
public async Task<IActionResult> AddAsync(CancellationToken ct)
{
var aModel= new A();
var bModel= new B();
if (await TryUpdateModelAsync<A>(aModel))
{
_logger.LogDebug($"Model binded to A");
return Ok(aModel);
}
else if (await TryUpdateModelAsync<B>(bModel))
{
_logger.LogDebug($"Model binded to B");
return Ok(bModel);
}
_logger.LogDebug("Nothing binded!");
return BadRequest();
}
But this approach failed. Is there a proper way to implement this kind of solution?
By the way I'm using this to reduce complexity of my endpoints, I want to update a record partially and by doing this, each model will map the same record but with different logics.
Any suggestions will be appreciated. Thanks.
Couldn't manage to provide elegant way to do this but here is what I've done so far, It works but seems a little ugly in my opinion.
I changed the action method to this:
[HttpPost(Name = Add)]
[AllowAnonymous]
public IActionResult AddSync([FromBody] JObject body)
{
var aModel = JsonConvert.DeserializeObject<A>(body.ToString());
var bModel = JsonConvert.DeserializeObject<B>(body.ToString());
ModelState.Clear();
var aValid = TryValidateModel(aModel);
ModelState.Clear();
var bValid = TryValidateModel(bModel);
// some logic here...
return Ok(new {aModel,bModel, aValid, bValid });
}
I think It's not a good idea to interfere with ModelState this way.
But here is what I've done,
get the raw body of the request as JObject (requires Newtonsoft.Json package)
Parsed that json value to candidate objects
Check their validity via modelstate and decide which one to use.

Use MEF to compose parts but postpone the creation of the parts

As explained in these questions I'm trying to build an application that consists of a host and multiple task processing clients. With some help I have figured out how to discover and serialize part definitions so that I could store those definitions without having to have the actual runtime type loaded.
The next step I want to achieve (or next two steps really) is that I want to split the composition of parts from the actual creation and connection of the objects (represented by those parts). So if I have a set of parts then I would like to be able to do the following thing (in pseudo-code):
public sealed class Host
{
public CreationScript Compose()
{
CreationScript result;
var container = new DelayLoadCompositionContainer(
s => result = s);
container.Compose();
return script;
}
public static void Main()
{
var script = Compose();
// Send the script to the client application
SendToClient(script);
}
}
// Lives inside other application
public sealed class Client
{
public void Load(CreationScript script)
{
var container = new ScriptLoader(script);
container.Load();
}
public static void Main(string scriptText)
{
var script = new CreationScript(scriptText);
Load(script);
}
}
So that way I can compose the parts in the host application, but actually load the code and execute it in the client application. The goal is to put all the smarts of deciding what to load in one location (the host) while the actual work can be done anywhere (by the clients).
Essentially what I'm looking for is some way of getting the ComposablePart graph that MEF implicitly creates.
Now my question is if there are any bits in MEF that would allow me to implement this kind of behaviour? I suspect that the provider model may help me with this but that is a rather large and complex part of MEF so any guidelines would be helpful.
From lots of investigation it seems that is not possible to separate the composition process from the instantiation process in MEF so I have had to create my own approach for this problem. The solution assumes that the scanning of plugins results in having the type, import and export data stored somehow.
In order to compose parts you need to keep track of each part instance and how it is connected to other part instances. The simplest way to do this is to make use of a graph data structure that keeps track of which import is connected to which export.
public sealed class CompositionCollection
{
private readonly Dictionary<PartId, PartDefinition> m_Parts;
private readonly Graph<PartId, PartEdge> m_PartConnections;
public PartId Add(PartDefinition definition)
{
var id = new PartId();
m_Parts.Add(id, definition);
m_PartConnections.AddVertex(id);
return id;
}
public void Connect(
PartId importingPart,
MyImportDefinition import,
PartId exportingPart,
MyExportDefinition export)
{
// Assume that edges point from the export to the import
m_PartConnections.AddEdge(
new PartEdge(
exportingPart,
export,
importingPart,
import));
}
}
Note that before connecting two parts it is necessary to check if the import can be connected to the export. In other cases MEF does that but in this case we'll need to do that ourselves. An example of how to approach that is:
public bool Accepts(
MyImportDefinition importDefinition,
MyExportDefinition exportDefinition)
{
if (!string.Equals(
importDefinition.ContractName,
exportDefinition.ContractName,
StringComparison.OrdinalIgnoreCase))
{
return false;
}
// Determine what the actual type is we're importing. MEF provides us with
// that information through the RequiredTypeIdentity property. We'll
// get the type identity first (e.g. System.String)
var importRequiredType = importDefinition.RequiredTypeIdentity;
// Once we have the type identity we need to get the type information
// (still in serialized format of course)
var importRequiredTypeDef =
m_Repository.TypeByIdentity(importRequiredType);
// Now find the type we're exporting
var exportType = ExportedType(exportDefinition);
if (AvailableTypeMatchesRequiredType(importRequiredType, exportType))
{
return true;
}
// The import and export can't directly be mapped so maybe the import is a
// special case. Try those
Func<TypeIdentity, TypeDefinition> toDefinition =
t => m_Repository.TypeByIdentity(t);
if (ImportIsCollection(importRequiredTypeDef, toDefinition)
&& ExportMatchesCollectionImport(
importRequiredType,
exportType,
toDefinition))
{
return true;
}
if (ImportIsLazy(importRequiredTypeDef, toDefinition)
&& ExportMatchesLazyImport(importRequiredType, exportType))
{
return true;
}
if (ImportIsFunc(importRequiredTypeDef, toDefinition)
&& ExportMatchesFuncImport(
importRequiredType,
exportType,
exportDefinition))
{
return true;
}
if (ImportIsAction(importRequiredTypeDef, toDefinition)
&& ExportMatchesActionImport(importRequiredType, exportDefinition))
{
return true;
}
return false;
}
Note that the special cases (like IEnumerable<T>, Lazy<T> etc.) require determining if the importing type is based on a generic type which can be a bit tricky.
Once all the composition information is stored it is possible to do the instantiation of the parts at any point in time because all the required information is available. Instantiation requires a generous helping of reflection combined with the use of the trusty Activator class and will be left as an exercise to the reader.

Doing some restapi in VB.Net and stuck on something

I doubt anyone has specific experience related to this particular task, but maybe you can spot my problem. I'm trying to make a call to lithium (forum software) to place a vote in their poll, and their docs show this:
Example URL:
http://community.lithium.com/community-name/restapi/vc/polls/id/15/votes/place
Query Arguments:
poll.choice (required): - the choice to place the vote for. The choice is specified by a string of the form id/choice_id where choice_id is the id of the poll choice
Http Method:
POST
So my code looks something like this:
Dim _Response As New XmlDocument
Dim RestApiRoot As String = "http://example.com/community-name/restapi/vc/polls/id/6/votes/place"
APIRequest = WebRequest.Create(RestApiRoot)
APIRequest.Method = "POST"
APIRequest.Headers.Add("poll.choice", HttpContext.Current.Server.UrlEncode("id/" & _choiceID.ToString))
APIResponse = APIRequest.GetResponse()
APIReader = New StreamReader(APIResponse.GetResponseStream())
_Response.LoadXml(APIReader.ReadToEnd())
APIResponse.Close()
I'm not able to successfully register a vote and they say it's because the poll.choice param is not appearing in the header, but if I step through debugging, I see it in the Header Keys/Items just fine.
Anyone have any clue what I might be doing wrong?
I do exactly this with RestSharp, an open source REST framework. It works great with the Lithium REST API.
You're code will look something like this using RestSharp:
You'll create a class to look like the response from the Lithium API, in this case "Response". It will look like this (sorry, you'll have to translate this to VB.NET):
public class LithiumResponse
{
public string status { get; set; }
public string value { get; set; }
public string message { get; set; }
}
Now RestSharp will use that to capture the result like this:
// create the request
var request = new RestRequest();
request.Verb = Method.POST;
request.BaseUrl = "http://example.com/community-name";
// specify the action
request.Action = "restapi/vc/polls/id/6/votes/place";
// add the parameters
request.AddParameter("poll.choice", "id/" + _choiceID.ToString());
// now create a RestClient to execute the request,
// telling it to put the results in your "reponse" class
var client = new RestClient();
var lithiumresponse = client.Execute<LithiumResponse>(request);
// now you can check the status property of your class to
// see if it was successful
if (lithiumresponse.status == "success")
// you successfully placed a vote
I use RestSharp for a lot of interaction with the Lithium API and it makes it brain-dead simple. Pretty awesome library.

Can I stop my WCF generating ArrayOfString instead of string[] or List<string>

I am having a minor problem with WCF service proxies where the message contains List<string> as a parameter.
I am using the 'Add Service reference' in Visual Studio to generate a reference to my service.
// portion of my web service message
public List<SubscribeInfo> Subscribe { get; set; }
public List<string> Unsubscribe { get; set; }
These are the generated properties on my MsgIn for one of my web methods.
You can see it used ArrayOfString when I am using List<string>, and the other takes List<SubscribeInfo> - which matches my original C# object above.
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
public System.Collections.Generic.List<DataAccess.MailingListWSReference.SubscribeInfo> Subscribe {
get {
return this.SubscribeField;
}
set {
if ((object.ReferenceEquals(this.SubscribeField, value) != true)) {
this.SubscribeField = value;
this.RaisePropertyChanged("Subscribe");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute(EmitDefaultValue=false)]
publicDataAccess.MailingListWSReference.ArrayOfString Unsubscribe {
get {
return this.UnsubscribeField;
}
set {
if ((object.ReferenceEquals(this.UnsubscribeField, value) != true)) {
this.UnsubscribeField = value;
this.RaisePropertyChanged("Unsubscribe");
}
}
}
The ArrayOfString class generated looks like this. This is a class generated in my code - its not a .NET class. It actually generated me a class that inherits from List, but didn't have the 'decency' to create me any constructors.
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.CollectionDataContractAttribute(Name="ArrayOfString", Namespace="http://www.example.com/", ItemName="string")]
[System.SerializableAttribute()]
public class ArrayOfString : System.Collections.Generic.List<string> {
}
The problem is that I often create my message like this :
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.ToList()
});
I really like the clean look this gives me.
Now for the actual problem :
I cant assign a List<string> to the Unsubscribe property which is an ArrayOfString - even though it inherits from List. In fact I cant seem to find ANY way to assign it without extra statements.
I've tried the following :
new ArrayOfString(unsubscribeFrom.ToList()) - this constructor doesn't exist :-(
changing the type of the array used by the code generator - doesn't work - it always gives me ArrayOfString (!?)
try to cast List<string> to ArrayOfString - fails with 'unable to cast', even though it compiles just fine
create new ArrayOfString() and then AddRange(unsubscribeFrom.ToList()) - works, but I cant do it all in one statement
create a conversion function ToArrayOfString(List<string>), which works but isn't as clean as I want.
Its only doing this for string, which is annoying.
Am i missing something? Is there a way to tell it not to generate ArrayOfString - or some other trick to assign it ?
Any .NET object that implements a method named "Add" can be initialized just like arrays or dictionaries.
As ArrayOfString does implement an "Add" method, you can initialize it like this:
var a = new ArrayOfString { "string one", "string two" };
But, if you really want to initialize it based on another collection, you can write a extension method for that:
public static class U
{
public static T To<T>(this IEnumerable<string> strings)
where T : IList<string>, new()
{
var newList = new T();
foreach (var s in strings)
newList.Add(s);
return newList;
}
}
Usage:
client.UpdateMailingList(new UpdateMailingListMsgIn()
{
Email = model.Email,
Name = model.Name,
Source = Request.Url.ToString(),
Subscribe = subscribeTo.ToList(),
Unsubscribe = unsubscribeFrom.To<ArrayOfString>()
});
I prefer not to return generic types across a service boundary in the first place. Instead return Unsubscribe as a string[], and SubscriptionInfo as SubscriptionInfo[]. If necessary, an array can easily be converted to a generic list on the client, as follows:
Unsubscribe = new List<string>(unsubscribeFrom);
Subscribe = new List<SubscriptionInfo>(subscribeTo);
Too late but can help people in the future...
Use the svcutil and explicitly inform the command line util that you want the proxy class to be serialized by the XmlSerializer and not the DataContractSerializer (default). Here's the sample:
svcutil /out:c:\Path\Proxy.cs /config:c:\Path\Proxy.config /async /serializer:XmlSerializer /namespace:*,YourNamespace http://www.domain.com/service/serviceURL.asmx
Note that the web service is an ASP.NET web service ok?!
If you are using VS 2008 to consume service then there is an easy solution.
Click on the "Advanced..." button on the proxy dialog that is displayed when you add a Service Reference. In the Collection Type drop down you can select System.Generic.List. The methods returning List should now work properly.
(Hope this is what you were asking for, I'm a little tired and the question was a tad difficult for me to read.)