I'm integrating payUMoney in my Android application. I'm getting only paymentId after successful payment in both environment i.e Test & Production. I need Transaction Details as well from payUMoney. I have also contacted payUMoney technical team but not getting any response.
See image attached for payUMoney response which I have printed in Logcat.
What I have tried is like below.
public void makePayment() {
String phone = "8882434664";
String productName = "product_name";
String firstName = "piyush";
String txnId = "0nf7" + System.currentTimeMillis();
String email = "piyush.jain#payu.in";
String sUrl = AppConstant.BASE_URL + "/mob-payment/success";
String fUrl = AppConstant.BASE_URL + "/mob-payment/failure";
String udf1 = "";
String udf2 = "";
String udf3 = "";
String udf4 = "";
String udf5 = "";
boolean isDebug = true;
String key = "dRQuiA";
String merchantId = "4928174";
PayUmoneySdkInitilizer.PaymentParam.Builder builder = new PayUmoneySdkInitilizer.PaymentParam.Builder();
builder.setAmount(1.0)
.setTnxId(txnId)
.setPhone(phone)
.setProductName(productName)
.setFirstName(firstName)
.setEmail(email)
.setsUrl(sUrl)
.setfUrl(fUrl)
.setUdf1(udf1)
.setUdf2(udf2)
.setUdf3(udf3)
.setUdf4(udf4)
.setUdf5(udf5)
.setIsDebug(isDebug)
.setKey(key)
.setMerchantId(merchantId);
PayUmoneySdkInitilizer.PaymentParam paymentParam = builder.build();
calculateServerSideHashAndInitiatePayment(paymentParam);
}
private void calculateServerSideHashAndInitiatePayment(final PayUmoneySdkInitilizer.PaymentParam paymentParam) {
String url = "https://test.payumoney.com/payment/op/calculateHashForTest";
StringRequest jsonObjectRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
if (jsonObject.has(SdkConstants.STATUS)) {
String status = jsonObject.optString(SdkConstants.STATUS);
if (status != null || status.equals("1")) {
String hash = jsonObject.getString(SdkConstants.RESULT);
paymentParam.setMerchantHash(hash);
PayUmoneySdkInitilizer.startPaymentActivityForResult(ActivityConfirmOrder.this, paymentParam);
} else {
Toast.makeText(ActivityConfirmOrder.this,
jsonObject.getString(SdkConstants.RESULT),
Toast.LENGTH_SHORT).show();
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error instanceof NoConnectionError) {
Toast.makeText(ActivityConfirmOrder.this,
ActivityConfirmOrder.this.getString(R.string.connect_to_internet),
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(ActivityConfirmOrder.this,
error.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
}) {
#Override
protected Map<String, String> getParams() throws AuthFailureError {
return paymentParam.getParams();
}
};
Volley.newRequestQueue(this).add(jsonObjectRequest);
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PayUmoneySdkInitilizer.PAYU_SDK_PAYMENT_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
StringBuilder str = new StringBuilder();
Bundle bundle = data.getExtras();
if (bundle != null) {
Set<String> keys = bundle.keySet();
Iterator<String> it = keys.iterator();
while (it.hasNext()) {
String key = it.next();
str.append(key);
str.append(":");
str.append(bundle.get(key));
str.append("\n\r");
}
Log.e("res: ", str.toString());
}
} else if (resultCode == RESULT_CANCELED) {
} else if (resultCode == PayUmoneySdkInitilizer.RESULT_FAILED) {
if (data != null) {
if (data.getStringExtra(SdkConstants.RESULT).equals("cancel")) {
} else {
}
}
} else if (resultCode == PayUmoneySdkInitilizer.RESULT_BACK) {
}
}
}
PayUMoney SDK-Version: versionName "6.1.0"
I was also facing the same problem, but after little bit of research, I have found that we need to generate invoice separately using different invoice api. You can find the bellow URL for the documentation for invoice api...
https://www.payumoney.com/dev-guide/products/invoicing.html
#MaulikDodia Actually you need to create success url on your own, then the payumoney will send all the data directly like this in your success url...
Array
(
[mihpayid] => 40399371551*******
[mode] => DC
[status] => success
[unmappedstatus] => captured
[key] => d****A
[txnid] => INV0****0531
[amount] => 1000.0
[addedon] => 2017-05-31 13:16:12
[productinfo] => ****
[firstname] => ****
[lastname] =>
[address1] =>
[address2] =>
[city] => null
[state] =>
[country] => null
[zipcode] =>
[email] => ***#test.xxx
[phone] =>
[udf1] =>
[udf2] =>
[udf3] =>
[udf4] =>
[udf5] =>
[udf6] =>
[udf7] =>
[udf8] =>
[udf9] =>
[udf10] =>
[hash] => ***************
[field1] => 715140****61
[field2] => 99***9
[field3] => 8523310*****511
[field4] => -1
[field5] =>
[field6] =>
[field7] =>
[field8] =>
[field9] => SUCCESS
[PG_TYPE] => HDFCPG
[encryptedPaymentId] => DB****EB8****02A****9FE4C****CB3
[bank_ref_num] => 8****016137****
[bankcode] => MAST
[error] => E000
[error_Message] => No Error
[name_on_card] => payu
[cardnum] => 512345XXXXXXXX46
[cardhash] => This field is no longer supported in postback params.
[amount_split] => {"PAYU":"1000.0"}
[payuMoneyId] => 1******0
[discount] => 0.00
[net_amount_debit] => 1000
)
Then you can generate invoice using that on the server side or do whatever you want.
Source: I have done all the code and it is working. Hope it helps... thanks
Related
I upgraded the source code to .NET Core v3.1 & I'm having trouble figuring how to debug the backend issue due to lot of dependency injections, abstractions & overriding classes/methods all over. The employee who wrote this have overcomplicate things & he had left the company so we got stuck with the confusing source code mess here that take a lot of our time & energy, to make sense of the it. :-/
The error I'm having is a 401 unauthorize response. I discovered the debugger doesnt respond in StartUp class when consuming the webservice, it only respond when you start up the Web App. So, it took us a while & finally found a hitting debugger breakpoint on a MVC controller page to point us in the right direction. There it is saying the Identity is not authenticated so that explain the unauthorize error.
We're not familiar with this one authentication technology, Odachi. We believe there are 2 seperate authentication architecture, which is ehe WebApp's webpages login authorization for the customer's web browser & Odachi deal with the WebApp's webservice login authorization for the 3rd party software making the webservice call.
Source code below is the webservice MVC controller w/ Authorization filter. Then further down will be the Startup w/ base Startup abstraction.
[ Webservice call ]
namespace ABC.Payments.AspNet.MVC
{
public class AuthorizeWithNoChallengeFilterAttribute : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.HttpContext.User?.Identity.IsAuthenticated != true)
context.Result = new UnauthorizedResult();
}
}
}
namespace ABC.Payments.MerchantWeb.Api
{
[TypeFilter(typeof(AuthorizeWithNoChallengeFilterAttribute))]
public class MerchantsV1Controller : Controller
{
[Route("api/v1/merchants/{merchantAccountId}/customers/payments/paymentmethods"), HttpPost]
public async Task<ObjectResult> Payment([FromBody] ItemInfoViewModel itemInfo, CancellationToken cancellationToken)
{
var payments = whatever();
return new HttpNotAcceptableObjectResult(payments);
}
}
}
[ Startup & Startup Base ]
namespace ABC.Payments.MerchantWeb
{
// StackOverflow Post on how to find 401 Unathorize error (debug)
// --> https://stackoverflow.com/questions/43574552/authorization-in-asp-net-core-always-401-unauthorized-for-authorize-attribute
public class Startup : StartupBase<MerchantRequestContext, Merchant>
{
private const string _schemeCustomMerchantBasic = "CustomMerchantBasic";
public Startup(IWebHostEnvironment webHostEnvironment)
: base(webHostEnvironment, PortalRoleType.Merchant)
{
}
public void ConfigureServices(IServiceCollection services)
{
base._configureServices(true, services);
services.AddTransient(sp => sp.GetService<MerchantRequestContext>()?.Merchant);
services.AddTransient(sp => sp.GetService<MerchantRequestContext>()?.Customer);
services.AddTransient(sp => sp.GetService<MerchantRequestContext>()?.TenantSettings);
services.AddLocalization(options =>
{
options.ResourcesPath = "Resources";
});
services.AddMvcCore()
.AddViewLocalization(LanguageViewLocationExpanderFormat.SubFolder, setup =>
{
setup.ResourcesPath = "Resources";
})
.AddDataAnnotationsLocalization()
.AddApiExplorer();
services.AddCors(options =>
{
options.AddPolicy("Internal", p => p.WithOrigins(base._configuration["Cors:InternalSource"]).WithMethods("POST").WithHeaders("accept", "request", "authorization", "content-type", "internal"));
});
services.AddAuthentication()
// https://github.com/Kukkimonsuta/Odachi/blob/master/src/Odachi.AspNetCore.Authentication.Basic/Events/BasicSignInContext.cs (Basic Sign Context)
// https://github.com/Kukkimonsuta/Odachi/blob/master/samples/BasicAuthenticationSample/Startup.cs
.AddBasic(_schemeCustomMerchantBasic, options =>
{
// ////////Notice: AutomaticChallenge is depreciated, google search said to use DefaultChallengeScheme w/ given cookie-authentication-scheme but that still doesnt explain how to disable it
// //////// https://stackoverflow.com/questions/45878166/asp-net-core-2-0-disable-automatic-challenge
// //////// https://github.com/dotnet/aspnetcore/issues/2007
//## options.AutomaticChallenge = false;
options.Realm = "AutoPayment API v1";
options.Events = new BasicEvents()
{
OnSignIn = async context =>
{
var claims = new List<Claim>();
if (context.Username == "ndi3DanDba993nvbaqbn3d93" && context.Password == "aVd3Ed51dfDE5acCCni9l1IxPq9")
claims.Add(new Claim(ClaimTypes.Role, "InternalAPIUser"));
else
{
string merchantAccountId = context.Request.Path.Value.Split('/').Skip(4).FirstOrDefault();
var merchantRepository = context.HttpContext.RequestServices.GetRequiredService<IMerchantRepository>();
if (merchantAccountId == null || merchantAccountId.Length != 14 || merchantAccountId.Split('-').Length != 3)
throw new Exception($"Invalid merchant account Id ({merchantAccountId ?? string.Empty}).");
var merchant = await merchantRepository.GetMerchantAsync(merchantAccountId, context.HttpContext.RequestAborted);
if (merchant == null || !merchant.IsActive || (merchant.GatePayApiKey != context.Username || merchant.GatePayApiSecret != context.Password))
{
context.Fail("Invalid merchant"); //## context.HandleResponse();
return;
}
}
var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, context.Scheme.Name)); //## options.AuthenticationScheme));
context.Principal = principal;
//## context.Ticket = new AuthenticationTicket(principal, new AuthenticationProperties(), options.AuthenticationScheme);
context.Success(); //## context.HandleResponse();
//return Task.CompletedTask;
}
};
});
}
public void Configure(IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
base._configure(true, applicationBuilder, loggerFactory, serviceProvider);
applicationBuilder.UseCors("Internal");
applicationBuilder.UseWhen(context => !context.Request.Path.StartsWithSegments(new PathString("/api/v1")), b => b.UseAuthentication());
}
}
}
namespace ABC.Payments
{
public class StartupBase<TRequestContext, TUserContext>
where TRequestContext : RequestContext<TUserContext>
{
public StartupBase(IWebHostEnvironment webHostEnvironment, PortalRoleType portalRoleType)
{
_portalRoleType = portalRoleType;
_webHostEnvironment = webHostEnvironment;
var builder = new ConfigurationBuilder();
ConfigurationLoader.Load(builder, webHostEnvironment);
_configuration = builder.Build();
if (webHostEnvironment.EnvironmentName.Equals("Production", StringComparison.OrdinalIgnoreCase) == true && _configuration["ConfirmProduction"]?.Equals("Yes", StringComparison.OrdinalIgnoreCase) != true)
throw new Exception("Azure defaults to \"Production\" for the environment, so you need to create an AppSetting of \"ConfirmProduction\" to \"Yes\" to ensure that is the intent.");
}
private readonly IWebHostEnvironment _webHostEnvironment;
public readonly IConfiguration _configuration;
private readonly PortalRoleType _portalRoleType;
public void _configureServices(bool isWebBrowserFrontendGui, IServiceCollection services)
{
if (isWebBrowserFrontendGui)
{
services.AddDistributedRedisCache(options =>
{
options.Configuration = _configuration["Storage:Redis:Configuration"];
});
services.AddSingleton<RedisCache>();
services.AddSingleton<MemoryDistributedCache>();
services.AddSingleton<IDistributedCache>(
sp => new ResilientDistributedCache(sp.GetRequiredService<RedisCache>(), sp.GetRequiredService<MemoryDistributedCache>())
);
var azureBlobConnectionTring = _configuration["Storage:AzureBlob:ConnectionString"];
if (azureBlobConnectionTring != null)
{
var storageAccount = CloudStorageAccount.Parse(azureBlobConnectionTring);
var client = storageAccount.CreateCloudBlobClient();
var azureBlobContainer = client.GetContainerReference("dataprotection-key-container");
services.AddDataProtection().PersistKeysToAzureBlobStorage(azureBlobContainer, "keys.xml");
}
services.AddSession(options =>
{
//options.IdleTimeout = TimeSpan.FromMinutes(5);
});
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole<Guid>>()
.AddEntityFrameworkStores<ApplicationContext>() // FYI - AddEntityFrameworkStores() deal with role that derives from IdentityRole, as per documentation.
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options => {
options.LoginPath = new PathString("/Home/Index");
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(_configuration.GetValue<int?>("Authentication:SlidingExpirationTime").Value);
options.AccessDeniedPath = new PathString("/Home/AccessDenied");
});
services.Configure<IdentityOptions>(options => {
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireDigit = false;
options.Password.RequiredLength = 7;
});
services.AddControllersWithViews();
services.AddRazorPages();
// AddMvc() vs AddMvcCore() explaination found at --> https://offering.solutions/blog/articles/2017/02/07/the-difference-between-addmvc-and-addmvccore/
// --> https://stackoverflow.com/questions/42365275/how-to-implement-a-pure-asp-net-core-web-api-by-using-addmvccore/42365276#42365276
services.AddMvc().AddRazorRuntimeCompilation();
services.Configure<MvcRazorRuntimeCompilationOptions>();
services.Configure<AuthorizationOptions>(options =>
{
options.DefaultPolicy = AuthorizationPolicy.Combine(options.DefaultPolicy,
new AuthorizationPolicy(new IAuthorizationRequirement[] {
new RolesAuthorizationRequirement(new string[] { _portalRoleType.ToString(), PortalRoleType.Internal.ToString() }),
new ImpersonationNotExpiredAuthorizationRequirement(_portalRoleType, _configuration.GetValue<TimeSpan?>("Authentication:ImpersonationTimeLimit").Value)
}, new string[0]));
});
services.AddMvcCore(options =>
{
var requestContextAttribute = new LoadRequestContextAttribute(typeof(TRequestContext));
options.Filters.Add(requestContextAttribute);
options.ModelBinderProviders[options.ModelBinderProviders.IndexOf(
options.ModelBinderProviders.OfType<ComplexTypeModelBinderProvider>().First()
)] = new TryServicesModelBinderProvider(services.BuildServiceProvider());
options.ModelBinderProviders.Insert(0, new EnumModelBinderProvider(services.BuildServiceProvider()));
})
.AddDataAnnotationsLocalization()
.AddNewtonsoftJson(settings =>
{
settings.SerializerSettings.ContractResolver = new DefaultContractResolver();
});
services.Configure<ForwardedHeadersOptions>(options => options.RequireHeaderSymmetry = false);
}
//services.AddPayments<TRequestContext, TUserContext>(_configuration, string.Empty);
}
public void _configure(bool isWebBrowserFrontendGui, IApplicationBuilder applicationBuilder, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
if (isWebBrowserFrontendGui)
{
serviceProvider.GetRequiredService<ITelemeter<StartupBase>>().TrackMetric("Startup Time", (DateTime.UtcNow - DateTime.UtcNow).TotalSeconds);
// Exception Page Handling.
if (!_webHostEnvironment.IsProduction())
{
applicationBuilder.UseDeveloperExceptionPage();
//applicationBuilder.UseDatabaseErrorPage();
}
else
applicationBuilder.UseExceptionHandler("/Home/ErrorPage.html");
applicationBuilder.UseStaticFiles(); // Note, we are not authenticating for static files if this is before them
//applicationBuilder.UseStatusCodePages();
// Session.
applicationBuilder.UseSession();
applicationBuilder.UseAuthentication();
// Routing.
applicationBuilder.UseRouting();
applicationBuilder.UseAuthorization(); // Exception error said to put this between UseRouting() & UseEnpoint().
applicationBuilder.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
// Config Localization.
var options = serviceProvider.GetService<IOptions<RequestLocalizationOptions>>();
if (options != null)
applicationBuilder.UseRequestLocalization(options.Value);
applicationBuilder.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.All });
// Ensure Https.
var portals = applicationBuilder.ApplicationServices.GetRequiredService<Portals>();
applicationBuilder.Use(next => async httpContext =>
{
if (httpContext.Request.Host.Value.Contains("localhost"))
{
await next(httpContext);
}
else
{
string host = portals.GetHostForRedirect(httpContext.Request.Host.Value);
if (!host.Equals((httpContext.Request.IsHttps ? "https://" : "http://") + httpContext.Request.Host, StringComparison.OrdinalIgnoreCase))
httpContext.Response.Redirect($"{host}{httpContext.Request.Path}{httpContext.Request.QueryString}");
else
await next(httpContext);
}
});
}
//applicationBuilder.UsePayments<TRequestContext, TUserContext>();
}
}
}
We are using RabbitMQ and MassTransit to exchange messages between publishers and consumers. Sometimes we are getting below exception message and then our all message transmissions are suddenly stopping. I am posting also our bus configuration code below.
One or more errors occurred. (Timeout waiting for response,
RequestId: 00c60000-0aff-0242-e641-08d6a323ec24)",
"MassTransit.RequestTimeoutException: Timeout waiting for response,
RequestId: 00c60000-0aff-0242-e641-08d6a323ec24 at MassTransit.Clients.ResponseHandlerConnectHandle`1.GetTask()
at MassTransit.Clients.ClientRequestHandle`1.HandleFault() at MassTransit.Clients.ResponseHandlerConnectHandle`1.GetTask()
at MassTransit.Clients.RequestClient`1.GetResponse[T](TRequest message, CancellationToken cancellationToken, RequestTimeout timeout)
Here is our bus configuration
service.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
if (startQuartz)
{
startQuartz = false;
MicroServiceConfig.MicroServiceHost.StartScheduledServices();
}
var config = provider.GetRequiredService<SLOTServerConfiguration>();
var vh = GetVirtualHost(config);
var url = config.RabbitMQHost + (config.RabbitMQHost.EndsWith("/") ? "" : "/") + vh;
var host = cfg.Host(new Uri(url), hst =>
{
hst.Username(config.RabbitMQUserName);
hst.Password(config.RabbitMQPassword);
});
if (!isApi)
{
cfg.AddReceiveEndpoint(host, provider, service, isApi);
host.ConnectConsumeObserver(new UserObserver());
host.ConnectSendObserver(new ErrorObserver());
}
}));
service.AddSingleton<IPublishEndpoint>(provider => provider.GetRequiredService<IBusControl>());
service.AddSingleton<ISendEndpointProvider>(provider => provider.GetRequiredService<IBusControl>());
service.AddSingleton<IBus>(provider => provider.GetRequiredService<IBusControl>());
service.AddSingleton<IHostedService, BusService>();
service.AddMassTransit(x =>
{
var method = x.GetType().GetMethod("AddConsumer");
foreach (var item in RegisteredTypes)
{
method.MakeGenericMethod(item.ConsumerType).Invoke(x, new object[0]);
}
});
}
private static void AddReceiveEndpoint(this IRabbitMqBusFactoryConfigurator cfg, IRabbitMqHost host, IServiceProvider provider, IServiceCollection service, bool registerClient)
{
var queueName = DateTime.Now.ToFileTimeUtc().ToString() + JsonConvert.SerializeObject(MicroServiceConfig.MicroServiceHost.ServiceNames).GetHashCode();
cfg.ReceiveEndpoint(host, queueName, e =>
{
e.AutoDelete = true;
e.PrefetchCount = 16;
e.UseMessageRetry(x => x.Interval(2, 100));
e.LoadFrom(provider);
});
}
private static string GetVirtualHost(SLOTServerConfiguration config)
{
var vh = config.RabbitMQVirtualHost;
if(string.IsNullOrEmpty(vh))
{
vh = Environment.MachineName;
}
}
Update :
Below you can find the publisher and consumer code blocks
var res = ThreadClient.GetResponse<AddExternalOutboundOrderListRequestModel, OutboundOrderResponseItem>(
_requestClient,
new ServerRequest<AddExternalOutboundOrderListRequestModel> { Model = model, Token = Request.Headers["token"] }
);
var ret = BaseResponseModel.Ok(res.Data, Request.Headers["RequestID"]);
ret.ExceptionMessage = res.ThreadExceptions;
return ret;
Consumer :
public Task Consume(ConsumeContext<ServerRequest<AddExternalOutboundOrderListRequestModel>> context)
{
var response = _outboundOrderWorkFlow.Add(context.Message.Model);
ServerResponse<OutboundOrderResponseItem> res = new ServerResponse<OutboundOrderResponseItem>
{
Data = response
};
context.Respond(res);
return Task.Delay(0);
}
The following linq query groups people in a city by their professions.
However the only way I've been able to get it to work is to hardcode the cities.
Each Person has a City. How can I modify the below query so that it groups by all the distinct cities that are returned in my query?
profession = people
.GroupBy(p => p.Profession).
Select(group =>
new
{
name = group.Key,
data =
new List<int>()
{
group.Count(p => p.City == "Adelaide"),
group.Count(p => p.City == "Brisbane"),
group.Count(p => p.City == "Canberra"),
group.Count(p => p.City == "Darwin"),
group.Count(p => p.City == "Melbourne"),
group.Count(p => p.City == "Perth"),
group.Count(p => p.City == "Sydney"),
},
})
Ie, if my data set was:
Person {id:1, city: "Paris" }
Person {id:2, city: "Paris" }
Person {id:3, city: "London" }
Then the resulting query would be:
profession = people
.GroupBy(p => p.Profession).
Select(group =>
new
{
name = group.Key,
data =
new List<int>()
{
group.Count(p => p.City == "Paris"),
group.Count(p => p.City == "London"),
},
})
This yields the same output as your hardcoded list, but I'm not sure if it's what you want (hint: giving us your expected output will help a lot in that regard).
It simply creates a distinct list of the cities, then builds a predicate delegate that counts the occurrence of each city, and adds that predicate to a list. When the actual grouping is performed, each predicate in the list is invoked with the result of the grouping.
The notation Func<IGrouping<string, Person>, int> simply says "this is a delegate that takes an IGrouping<string, Person> object (the result of calling GroupBy) and returns an int (the result of calling Count)".
class Program
{
static void Main(string[] args)
{
var people = new List<Person>()
{
new Person(1, "Paris", "carpenter"),
new Person(2, "Paris", "bricklayer"),
new Person(3, "London", "video game critic"),
};
var distinctCities = people.Select(p => p.City).Distinct();
var groupPredicates = new List<Func<IGrouping<string, Person>, int>>();
foreach (var city in distinctCities)
{
groupPredicates.Add(g => g.Count(p => p.City == city));
}
var professions = people
.GroupBy(p => p.Profession)
.Select(g =>
new
{
name = g.Key,
data = groupPredicates.Select(gp => gp(g)),
});
foreach (var profession in professions)
{
Console.WriteLine(profession.name + " =>");
foreach (var count in profession.data)
{
Console.WriteLine(" " + count);
}
}
Console.ReadKey(true);
}
}
struct Person
{
public int Id { get; set; }
public string City { get; set; }
public string Profession { get; set; }
public Person(int id, string city, string profession)
{
Id = id;
City = city;
Profession = profession;
}
}
I need to know what I've to do if I want to download a cmis:documento that I've in my repositorio with Apache Chemistry Php client.
I've one file, "Test.txt" in Sitios space...
I want download Test.txt with browser...
My code:
$client = new CMISService('http://localhost:8080/alfresco/api/-default-/public/cmis/versions/1.1/atom', 'admin', 'admin');
$path = '/Sitios';
$directorio = $client->getObjectByPath($path);
$objs = $client->getChildren($directorio->id);
foreach ($objs->objectList as $obj)
{
var_dump ($obj);
}
In $obj I've:
array (size=32)
'alfcmis:nodeRef' => string 'workspace://SpacesStore/c3c903fe-86b6-4db0-8cb2-d5c5dbe913c7' (length=60)
'cmis:isImmutable' => string 'false' (length=5)
'cmis:versionLabel' => string '1.0' (length=3)
'cmis:objectTypeId' => string 'cmis:document' (length=13)
'cmis:description' => string 'descripcion del fichero' (length=23)
'cmis:createdBy' => string 'admin' (length=5)
'cmis:checkinComment' => null
'cmis:creationDate' => string '2016-02-15T01:25:12.76+01:00' (length=28)
'cmis:isMajorVersion' => string 'true' (length=4)
'cmis:contentStreamFileName' => string 'Fichero de texto plano' (length=22)
'cmis:name' => string 'Fichero de texto plano' (length=22)
'cmis:isLatestVersion' => string 'true' (length=4)
'cmis:lastModificationDate' => string '2016-02-15T01:25:12.76+01:00' (length=28)
'cmis:contentStreamLength' => string '21' (length=2)
'cmis:objectId' => string 'c3c903fe-86b6-4db0-8cb2-d5c5dbe913c7;1.0' (length=40)
'cmis:lastModifiedBy' => string 'admin' (length=5)
'cmis:secondaryObjectTypeIds' => string 'P:rn:renditioned' (length=16)
'cmis:contentStreamId' => string 'store://2016/2/15/1/25/c36a749d-43f1-4e31-b46a-de66b4f5634d.bin' (length=63)
'cmis:contentStreamMimeType' => string 'text/plain' (length=10)
'cmis:baseTypeId' => string 'cmis:document' (length=13)
'cmis:changeToken' => null
'cmis:isPrivateWorkingCopy' => string 'false' (length=5)
'cmis:versionSeriesCheckedOutBy' => null
'cmis:isVersionSeriesCheckedOut' => string 'false' (length=5)
'cmis:versionSeriesId' => string 'c3c903fe-86b6-4db0-8cb2-d5c5dbe913c7' (length=36)
'cmis:isLatestMajorVersion' => string 'true' (length=4)
'cmis:versionSeriesCheckedOutId' => null
'cm:title' => string 'Titulo del fichero' (length=18)
'cm:description' => string 'descripcion del fichero' (length=23)
'app:editInline' => string 'true' (length=4)
'cm:lastThumbnailModification' => string 'pdf:1455495914744' (length=17)
'' => string 'Titulo del fichero' (length=18)
public 'renditions' =>
What I've to do to create a link to download the file?
I don't want to use webscript...
I think that I've to use getContentStream($obj->id) ¿really?
Thanks.
Depending on your document mime type and what you are willing to do with, it can be slightly different, but basically this is what you need to do, if you were using java:
// Get the contents of the file
Document doc = (Document) session.getObject(id);
ContentStream contentStream = doc.getContentStream(); // returns null if the document has no content
if (contentStream != null) {
String content = getContentAsString(contentStream);
System.out.println("Contents of " + filename + " are: " + content);
} else {
System.out.println("No content.");
}
...
/**
* Helper method to get the contents of a stream
*
* #param stream
* #return
* #throws IOException
*/
private static String getContentAsString(ContentStream stream) throws IOException {
StringBuilder sb = new StringBuilder();
Reader reader = new InputStreamReader(stream.getStream(), "UTF-8");
try {
final char[] buffer = new char[4 * 1024];
int b;
while (true) {
b = reader.read(buffer, 0, buffer.length);
if (b > 0) {
sb.append(buffer, 0, b);
} else if (b == -1) {
break;
}
}
} finally {
reader.close();
}
return sb.toString();
}
but since you are on PHP, I guess you should be replicating the same logic with php api fuctions, so basically $client->getContentStream($objId); should return the file content as string.
I'm just trying to use dictionary data to build query string. i use this function.
public static string BuildQueryString(this IDictionary<string, string> source, bool withoutEmptyString)
{
return source != null ? String.Join("&", source.Keys
.Where(key => !withoutEmptyString || source.Values.Any(value => !String.IsNullOrEmpty(value)))
.SelectMany(key => source.Values
.Where(value => !withoutEmptyString || !String.IsNullOrEmpty(value))
.Select(value => String.Format("{0}={1}", HttpUtility.UrlEncode(key), value != null ? HttpUtility.UrlEncode(value) : string.Empty)))
.ToArray())
: string.Empty;
}
but when i send the data like this
var dataDictionary = new Dictionary<string, string>
{ {"one", "1"},
{"two", "2"},
{"three", "3"},
{"four", "4"},
{"five", "5"},
{"six", "6"}
};
i'm getting string like this
"one=1&one=2&one=3&one=4&one=5&one=6&two=1&two=2&two=3&two=4&two=5&two=6&three=1&three=2&three=3&three=4&three=5&three=6&four=1&four=2&four=3&four=4&four=5&four=6&five=1&five=2&five=3&five=4&five=5&five=6&six=1&six=2&six=3&six=4&six=5&six=6"
what is the wrong i did in the code
thanks
How about something simpler like:
var fromSource = source.Where(s => !string.IsNullOrEmpty(s.Value)).Select(s => s.Key + "=" + s.Value);
return string.Join("&", fromSource.ToArray());
return source != null ? string.Join("&",
source.Where(keyValuePair => withoutEmptyString && !string.IsNullOrEmpty(keyValuePair.Value))
.Select(keyValuePair => string.Format("{0}={1}", keyValuePair.Key, keyValuePair.Value)))
: string.Empty;
Please check if my where clause works for you.